diff --git a/docs/references/bib.bib b/docs/references/bib.bib index 8fd09f1293b6..aedfb7683c45 100644 --- a/docs/references/bib.bib +++ b/docs/references/bib.bib @@ -251,7 +251,7 @@ @article{ahrens:1974 year = {1974}, } -@article{hormann:1993, +@article{hormann:1993a, abstract = {The transformed rejection method, a combination of inversion and rejection, which can be applied to various continuous distributions, is well suited to generate binomial random variates as well. The resulting algorithms are simple and fast, and need only a short set-up. Among the many possible variants two algorithms are described and tested: BTRS a short but nevertheless fast rejection algorithm and BTRD which is more complicated as the idea of decomposition is utilized. For BTRD the average number of uniforms required to return one binomial deviate less between 2.5 and 1.4 which is considerably lower than for any of the known uniformly fast algorithms. Timings for a C-implementation show that for the case that the parameters of the binomial distribution vary from call to call BTRD is faster than the current state of the art algorithms. Depending on the computer, the speed of the uniform generator used and the binomial parameters the savings are between 5 and 40 percent.}, author = {Wolfgang H\"{o}rmann}, doi = {10.1080/00949659308811496}, @@ -534,7 +534,7 @@ @book{knuth:1997 year = {1997}, } -@article{hormann:1993, +@article{hormann:1993b, abstract = {The transformed rejection method, a combination of the inversion and the rejection method, which is used to generate non-uniform random numbers from a variety of continuous distributions can be applied to discrete distributions as well. For the Poisson distribution a short and simple algorithm is obtained which is well suited for large values of the Poisson parameter \\(\mu\\), even when \\(\mu\\) may vary from call to call. The average number of uniform deviates required is lower than for any of the known uniformly fast algorithms. Timings for a C implementation show that the algorithm needs only half of the code but is - for \\(\mu\\) not too small - at least as fast as the current state-of-the-art algorithms.}, author = {W. H\"{o}rmann}, doi = {10.1016/0167-6687(93)90997-4}, diff --git a/lib/node_modules/@stdlib/math/base/random/binomial/README.md b/lib/node_modules/@stdlib/math/base/random/binomial/README.md index a42e449ae616..52f3eee1847a 100644 --- a/lib/node_modules/@stdlib/math/base/random/binomial/README.md +++ b/lib/node_modules/@stdlib/math/base/random/binomial/README.md @@ -146,7 +146,7 @@ for ( i = 0; i < 100; i++ ) { ## References -* Hörmann, Wolfgang. 1993. "The generation of binomial random variates." *Journal of Statistical Computation and Simulation* 46 (1-2): 101–10. doi:[10.1080/00949659308811496][@hormann:1993]. +* Hörmann, Wolfgang. 1993. "The generation of binomial random variates." *Journal of Statistical Computation and Simulation* 46 (1-2): 101–10. doi:[10.1080/00949659308811496][@hormann:1993a]. @@ -196,6 +196,6 @@ for ( i = 0; i < 100; i++ ) { [binomial]: https://en.wikipedia.org/wiki/Binomial_distribution -[@hormann:1993]: http://dx.doi.org/10.1080/00949659308811496 +[@hormann:1993a]: http://dx.doi.org/10.1080/00949659308811496 diff --git a/lib/node_modules/@stdlib/math/base/random/binomial/lib/binomial.js b/lib/node_modules/@stdlib/math/base/random/binomial/lib/binomial.js index 4cee9eb7efc9..7f834a22e8b3 100644 --- a/lib/node_modules/@stdlib/math/base/random/binomial/lib/binomial.js +++ b/lib/node_modules/@stdlib/math/base/random/binomial/lib/binomial.js @@ -13,13 +13,13 @@ var factory = require( './factory.js' ); * #### Method * * * For \\(np < 10\\), the function generates Bernoulli random variates and returns their sum. -* * For \\(np \geq 10\\), the function uses the [BTRD algorithm][@hormann:1993]. +* * For \\(np \geq 10\\), the function uses the [BTRD algorithm][@hormann:1993a]. * * #### References * -* * Hörmann, Wolfgang. 1993. "The generation of binomial random variates." *Journal of Statistical Computation and Simulation* 46 (1-2): 101–10. doi:[10.1080/00949659308811496][@hormann:1993]. +* * Hörmann, Wolfgang. 1993. "The generation of binomial random variates." *Journal of Statistical Computation and Simulation* 46 (1-2): 101–10. doi:[10.1080/00949659308811496][@hormann:1993a]. * -* [@hormann:1993]: http://dx.doi.org/10.1080/00949659308811496 +* [@hormann:1993a]: http://dx.doi.org/10.1080/00949659308811496 * * @name binomial * @type {Function} diff --git a/lib/node_modules/@stdlib/math/base/random/binomial/lib/sample2.js b/lib/node_modules/@stdlib/math/base/random/binomial/lib/sample2.js index fb402a55b9ab..b0a2a5905b85 100644 --- a/lib/node_modules/@stdlib/math/base/random/binomial/lib/sample2.js +++ b/lib/node_modules/@stdlib/math/base/random/binomial/lib/sample2.js @@ -22,9 +22,9 @@ var ONE_SIXTH = 1.0 / 6.0; * * #### References * -* * Hörmann, Wolfgang. 1993. "The generation of binomial random variates." *Journal of Statistical Computation and Simulation* 46 (1-2): 101–10. doi:[10.1080/00949659308811496][@hormann:1993]. +* * Hörmann, Wolfgang. 1993. "The generation of binomial random variates." *Journal of Statistical Computation and Simulation* 46 (1-2): 101–10. doi:[10.1080/00949659308811496][@hormann:1993a]. * -* [@hormann:1993]: http://dx.doi.org/10.1080/00949659308811496 +* [@hormann:1993a]: http://dx.doi.org/10.1080/00949659308811496 * * @private * @param {Function} rand - PRNG for uniformly distributed numbers diff --git a/lib/node_modules/@stdlib/math/base/random/exponential/README.md b/lib/node_modules/@stdlib/math/base/random/exponential/README.md index 36e7e4a0f20d..2e4a88a624ce 100644 --- a/lib/node_modules/@stdlib/math/base/random/exponential/README.md +++ b/lib/node_modules/@stdlib/math/base/random/exponential/README.md @@ -20,7 +20,7 @@ var r = exponential( 7.9 ); // returns ``` -If `lambda <= 0` or `lambda` is `NaN`, the function `NaN`. +If `lambda <= 0` or `lambda` is `NaN`, the function returns `NaN`. ``` javascript var r = exponential( -2.0 ); diff --git a/lib/node_modules/@stdlib/math/base/random/exponential/lib/factory.js b/lib/node_modules/@stdlib/math/base/random/exponential/lib/factory.js index 41990bf1a40c..3f9e660b4319 100644 --- a/lib/node_modules/@stdlib/math/base/random/exponential/lib/factory.js +++ b/lib/node_modules/@stdlib/math/base/random/exponential/lib/factory.js @@ -69,8 +69,7 @@ function factory() { } if ( lambda === void 0 ) { prng = exponential2; - } - else { + } else { prng = exponential1; } setReadOnly( prng, 'NAME', 'exponential' ); diff --git a/lib/node_modules/@stdlib/math/base/random/exponential/test/test.factory.js b/lib/node_modules/@stdlib/math/base/random/exponential/test/test.factory.js index fca19b5f49f5..16445b6a4cde 100644 --- a/lib/node_modules/@stdlib/math/base/random/exponential/test/test.factory.js +++ b/lib/node_modules/@stdlib/math/base/random/exponential/test/test.factory.js @@ -135,6 +135,7 @@ tape( 'the function throws an error if provided a rate which is not a positive n true, undefined, [], + {}, function(){} ]; diff --git a/lib/node_modules/@stdlib/math/base/random/geometric/test/test.factory.js b/lib/node_modules/@stdlib/math/base/random/geometric/test/test.factory.js index 101ffc88efca..3b6617ca489b 100644 --- a/lib/node_modules/@stdlib/math/base/random/geometric/test/test.factory.js +++ b/lib/node_modules/@stdlib/math/base/random/geometric/test/test.factory.js @@ -285,6 +285,6 @@ tape( 'the function returns a PRNG for generating random numbers from a geometri } } // Account for small sample sizes and few repeats... - t.ok( rejected / repeats < 0.10, 'null hypothesis (i.e., that numbers are drawn from Geometric('+p+') is rejected in less than 10% of cases ('+rejected+' of '+repeats+')' ); + t.ok( rejected / repeats < 0.12, 'null hypothesis (i.e., that numbers are drawn from Geometric('+p+') is rejected in less than 12% of cases ('+rejected+' of '+repeats+')' ); t.end(); }); diff --git a/lib/node_modules/@stdlib/math/base/random/package.json b/lib/node_modules/@stdlib/math/base/random/package.json index 086e6f9161b2..2c41251bbf60 100644 --- a/lib/node_modules/@stdlib/math/base/random/package.json +++ b/lib/node_modules/@stdlib/math/base/random/package.json @@ -1,7 +1,7 @@ { "name": "", "version": "", - "description": "Standard library random number generators.", + "description": "Standard library pseudorandom number generators.", "author": {}, "contributors": [], "scripts": {}, diff --git a/lib/node_modules/@stdlib/math/base/random/poisson/README.md b/lib/node_modules/@stdlib/math/base/random/poisson/README.md index f8688844b63d..d0223bfeb8ac 100644 --- a/lib/node_modules/@stdlib/math/base/random/poisson/README.md +++ b/lib/node_modules/@stdlib/math/base/random/poisson/README.md @@ -20,32 +20,51 @@ var r = poisson( 7.9 ); // returns ``` -If provided `lambda <= 0`, the function throws an error. +If `lambda <= 0` or `lambda` is `NaN`, the function returns `NaN`. ``` javascript var r = poisson( -2.0 ); -// throws TypeError +// returns NaN -r = poisson( 0.0 ); -// throws TypeError +r = poisson( NaN ); +// returns NaN ``` #### poisson.factory( \[lambda, \]\[options\] ) -Returns a pseudorandom number generator (PRNG) for generating pseudorandom numbers drawn from a [Poisson][poisson] distribution. If the mean parameter `lambda` is supplied, the returned generator returns random variates from the specified distribution, otherwise the parameter has to be supplied at each generator invocation. +Returns a pseudorandom number generator (PRNG) for generating pseudorandom numbers drawn from a [Poisson][poisson] distribution. ``` javascript -// Draw from Poisson(15) distribution: var rand = poisson.factory(); + var r = rand( 15.0 ); // returns +``` + +If provided `lambda`, the returned generator returns random variates from the specified distribution. + +``` javascript +var rand = poisson.factory( 10.0 ); + +var r = rand(); +// returns -// Draw from Poisson(10) distribution: -rand = poisson.factory( 10.0 ); r = rand(); // returns ``` +If not provided `lambda`, the returned generator requires that `lambda` be provided at each invocation. + +``` javascript +var rand = poisson.factory(); + +var r = rand( 4.0 ); +// returns + +r = rand( 3.14 ); +// returns +``` + The function accepts the following `options`: * __seed__: pseudorandom number generator seed. @@ -77,6 +96,15 @@ var name = poisson.NAME; // returns 'poisson' ``` +#### poisson.PRNG + +The underlying pseudorandom number generator. + +``` javascript +var prng = poisson.PRNG; +// returns +``` + #### poisson.SEED The value used to seed `poisson()`. @@ -102,12 +130,13 @@ for ( i = 0; i < 100; i++ ) { + ## References -* Donald E. Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Addison Wesley. -* Hörmann, W. (1993). The transformed rejection method for generating Poisson random variables. Insurance: Mathematics and Economics. +* Knuth, Donald E. 1997. *The Art of Computer Programming, Volume 2 (3rd Ed.): Seminumerical Algorithms*. Boston, MA, USA: Addison-Wesley Longman Publishing Co., Inc. +* Hörmann, W. 1993. "The transformed rejection method for generating Poisson random variables." *Insurance: Mathematics and Economics* 12 (1): 39–45. doi:[10.1016/0167-6687(93)90997-4][@hormann:1993b]. @@ -156,4 +185,6 @@ for ( i = 0; i < 100; i++ ) { [poisson]: https://en.wikipedia.org/wiki/Poisson_distribution +[@hormann:1993b]: http://dx.doi.org/10.1016/0167-6687(93)90997-4 + diff --git a/lib/node_modules/@stdlib/math/base/random/poisson/lib/_poisson.js b/lib/node_modules/@stdlib/math/base/random/poisson/lib/_poisson.js new file mode 100644 index 000000000000..d56c470bf4b4 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/random/poisson/lib/_poisson.js @@ -0,0 +1,29 @@ +'use strict'; + +// MODULES // + +var knuth = require( './knuth.js' ); +var rejection = require( './rejection.js' ); + + +// MAIN // + +/** +* Returns a pseudorandom number drawn from a Poisson distribution with parameter `lambda`. +* +* @private +* @param {Function} rand - PRNG for generating uniformly distributed numbers +* @param {PositiveNumber} lambda - mean +* @returns {NonNegativeInteger} pseudorandom number +*/ +function poisson( rand, lambda ) { + if ( lambda < 30.0 ) { + return knuth( rand, lambda ); + } + return rejection( rand, lambda ); +} // end FUNCTION poisson() + + +// EXPORTS // + +module.exports = poisson; diff --git a/lib/node_modules/@stdlib/math/base/random/poisson/lib/factory.js b/lib/node_modules/@stdlib/math/base/random/poisson/lib/factory.js index 29cf3b844e38..473497243848 100644 --- a/lib/node_modules/@stdlib/math/base/random/poisson/lib/factory.js +++ b/lib/node_modules/@stdlib/math/base/random/poisson/lib/factory.js @@ -3,37 +3,23 @@ // MODULES // var setReadOnly = require( '@stdlib/utils/define-read-only-property' ); -var factorialln = require( '@stdlib/math/base/special/factorialln' ); var isPositive = require( '@stdlib/utils/is-positive-number' ).isPrimitive; var isObject = require( '@stdlib/utils/is-plain-object' ); var randu = require( '@stdlib/math/base/random/randu' ).factory; -var floor = require( '@stdlib/math/base/special/floor' ); -var sign = require( '@stdlib/math/base/special/signum' ); -var sqrt = require( '@stdlib/math/base/special/sqrt' ); -var abs = require( '@stdlib/math/base/special/abs' ); -var exp = require( '@stdlib/math/base/special/exp' ); -var ln = require( '@stdlib/math/base/special/ln' ); -var LN_SQRT_TWO_PI = require( '@stdlib/math/constants/float64-ln-sqrt-two-pi' ); +var isnan = require( '@stdlib/math/base/utils/is-nan' ); +var poisson0 = require( './_poisson.js' ); -// FACTORY // +// MAIN // /** * Returns a pseudorandom number generator for generating Poisson distributed random numbers. * -* #### Method -* * When lambda < 30, use Knuth's method. -* * When lambda >= 30, use transformed rejection method as Knuth's method does not scale well with lambda. -* -* #### References -* * Donald E. Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Addison Wesley. -* * Hörmann, W. (1993). The transformed rejection method for generating Poisson random variables. Insurance: Mathematics and Economics. -* -* @param {PositiveNumber} [lambda] - mean parameter +* @param {PositiveNumber} [lambda] - mean * @param {Options} [options] - function options * @param {*} [options.seed] - pseudorandom number generator seed -* @throws {TypeError} lambda must be a positive number -* @throws {TypeError} options must be an object +* @throws {TypeError} `lambda` must be a positive number +* @throws {TypeError} options argument must be an object * @returns {Function} pseudorandom number generator * * @example @@ -55,51 +41,45 @@ var LN_SQRT_TWO_PI = require( '@stdlib/math/constants/float64-ln-sqrt-two-pi' ); */ function factory() { var lambda; - var nargs; - var args; var opts; var rand; - var ret; + var prng; - args = arguments; - nargs = args.length; - if ( nargs === 0 ) { + if ( arguments.length === 0 ) { rand = randu(); - } - else { - if ( isObject( args[ 0 ] ) ) { - opts = args[ 0 ]; + } else if ( + arguments.length === 1 && + isObject( arguments[ 0 ] ) + ) { + rand = randu( arguments[ 0 ] ); + } else { + lambda = arguments[ 0 ]; + if ( !isPositive( lambda ) ) { + throw new TypeError( 'invalid input argument. First argument must be a positive number. Value: `' + lambda + '`.' ); + } + if ( arguments.length > 1 ) { + opts = arguments[ 1 ]; + if ( !isObject( opts ) ) { + throw new TypeError( 'invalid input argument. Options argument must be an object. Value: `' + opts + '`.' ); + } rand = randu( opts ); } else { - lambda = args[ 0 ]; - if ( !isPositive( lambda ) ) { - throw new TypeError( 'invalid input argument. First argument `lambda` must be a positive number. Value: `' + lambda + '`.' ); - } - if ( nargs > 1 ) { - opts = args[ 1 ]; - if ( !isObject( opts ) ) { - throw new TypeError( 'invalid input argument. If supplied, second argument must be an options object. Value: `' + opts + '`.' ); - } - rand = randu( opts ); - } else { - rand = randu(); - } + rand = randu(); } } - - if ( lambda !== void 0 ) { - ret = poisson1; - } - else { - ret = poisson2; + if ( lambda === void 0 ) { + prng = poisson2; + } else { + prng = poisson1; } - setReadOnly( ret, 'NAME', 'poisson' ); - setReadOnly( ret, 'SEED', rand.SEED ); - setReadOnly( ret, 'PRNG', rand.PRNG ); - return ret; + setReadOnly( prng, 'NAME', 'poisson' ); + setReadOnly( prng, 'SEED', rand.SEED ); + setReadOnly( prng, 'PRNG', rand ); + + return prng; /** - * Returns Poisson random variates with bound parameter `lambda`. + * Returns a pseudorandom number drawn from a Poisson distribution. * * @private * @returns {NonNegativeInteger} pseudorandom number @@ -109,106 +89,37 @@ function factory() { * // returns */ function poisson1() { - return sampler( lambda ); + return poisson0( rand, lambda ); } // end FUNCTION poisson1() /** - * Performs type-checking and then calls sampler function to generate random number. + * Returns a pseudorandom number drawn from a Poisson distribution. * * @private - * @param {PositiveNumber} lambda - mean parameter - * @throws {TypeError} must provide a positive number + * @param {PositiveNumber} lambda - mean * @returns {NonNegativeInteger} pseudorandom number * * @example * var v = poisson2( 0.5 ); * // returns - */ - function poisson2( lambda ) { - if ( !isPositive( lambda ) ) { - throw new TypeError( 'invalid input argument. First argument `lambda` must be a positive number. Value: `' + lambda + '`.' ); - } - return sampler( lambda ); - } // end FUNCTION poisson2() - - /** - * Returns a random number drawn from a Poisson distribution with parameter `lambda`. * - * @private - * @param {PositiveNumber} lambda - mean parameter - * @returns {NonNegativeInteger} pseudorandom number + * @example + * var v = poisson2( NaN ); + * // returns NaN * * @example - * var v = sampler( 0.5 ); - * // returns + * var v = poisson2( -1.0 ); + * // returns NaN */ - function sampler( lambda ) { - var slambda; - var ainv; - var us; - var vr; - var l; - var p; - var k; - var b; - var a; - var u; - var v; - - slambda = sqrt( lambda ); - b = 0.931 + 2.54 * slambda; - a = -0.059 + 0.02483 * b; - ainv = 1.1239 + 1.1328 / ( b - 3.4 ); - vr = 0.9277 - 3.6224 / ( b - 2.0 ); - if ( lambda < 30.0 ) { - l = exp( -lambda ); - k = 0; - p = 1.0; - do { - k += 1; - u = rand(); - p *= u; - } while ( p > l ); - return k - 1; + function poisson2( lambda ) { + if ( + isnan( lambda ) || + lambda <= 0.0 + ) { + return NaN; } - return (function exec() { - v = rand(); - if ( v <= 0.86 * vr ) { - u = v / vr - 0.43; - return floor( ( 2.0*a / (0.5-abs(u) ) + b ) * u + lambda + 0.445 ); - } - if ( v >= vr ) { - u = rand() - 0.5; - } else { - u = v / vr - 0.93; - u = sign( u ) * 0.5 - u; - v = vr * rand(); - } - us = 0.5 - abs( u ); - if ( us < 0.013 && v > us ) { - return exec(); - } - k = floor( ( 2.0*a/us + b ) * u + lambda + 0.445 ); - v = v * ainv / ( a/(us*us) + b ); - if ( - k >= 10 && - ln( v * slambda ) <= (k+0.5) * ln(lambda/k) - - lambda - LN_SQRT_TWO_PI + k - (1/12-1/(360*k*k))/k - ) { - return k; - } - if ( - 0 <= k && - k <= 9 && - ln( v ) <= k * ln( lambda ) - lambda - factorialln( k ) - ) { - return k; - } else { - return exec(); - } - })(); - } // end FUNCTION sampler() - + return poisson0( rand, lambda ); + } // end FUNCTION poisson2() } // end FUNCTION factory() diff --git a/lib/node_modules/@stdlib/math/base/random/poisson/lib/knuth.js b/lib/node_modules/@stdlib/math/base/random/poisson/lib/knuth.js new file mode 100644 index 000000000000..d5b6da8b7d1d --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/random/poisson/lib/knuth.js @@ -0,0 +1,41 @@ +'use strict'; + +// MODULES // + +var exp = require( '@stdlib/math/base/special/exp' ); + + +// MAIN // + +/** +* Returns a pseudorandom number drawn from a Poisson distribution. +* +* #### Notes +* +* * Appropriate for \\(lambda < 30\\). +* +* +* #### References +* +* * Knuth, Donald E. 1997. *The Art of Computer Programming, Volume 2 (3rd Ed.): Seminumerical Algorithms*. Boston, MA, USA: Addison-Wesley Longman Publishing Co., Inc. +* +* +* @private +* @param {Function} rand - PRNG for generating uniformly distributed numbers +* @param {PositiveNumber} lambda - mean +* @returns {NonNegativeInteger} pseudorandom number +*/ +function poisson( rand, lambda ) { + var p = rand(); + var k = 1; + while ( p > exp( -lambda ) ) { + k += 1; + p *= rand(); + } + return k - 1; +} // end FUNCTION poisson() + + +// EXPORTS // + +module.exports = poisson; diff --git a/lib/node_modules/@stdlib/math/base/random/poisson/lib/poisson.js b/lib/node_modules/@stdlib/math/base/random/poisson/lib/poisson.js index f2e092954217..80636eed1df4 100644 --- a/lib/node_modules/@stdlib/math/base/random/poisson/lib/poisson.js +++ b/lib/node_modules/@stdlib/math/base/random/poisson/lib/poisson.js @@ -5,20 +5,40 @@ var factory = require( './factory.js' ); -// POISSON PRNG // +// MAIN // /** -* Returns a random number drawn from a Poisson distribution with parameter `lambda`. +* Returns a pseudorandom number drawn from a Poisson distribution with parameter `lambda`. * -* @function poisson +* #### Method +* +* * When \\(\lambda < 30\\), use Knuth's method. +* * When \\(lambda \geq 30\\), use transformed rejection method as Knuth's method does not scale well with \\(\lambda\\). +* +* #### References +* +* * Knuth, Donald E. 1997. *The Art of Computer Programming, Volume 2 (3rd Ed.): Seminumerical Algorithms*. Boston, MA, USA: Addison-Wesley Longman Publishing Co., Inc. +* * Hörmann, W. 1993. "The transformed rejection method for generating Poisson random variables." *Insurance: Mathematics and Economics* 12 (1): 39–45. doi:[10.1016/0167-6687(93)90997-4][@hormann:1993b]. +* +* [@hormann:1993b]: http://dx.doi.org/10.1016/0167-6687(93)90997-4 +* +* +* @name poisson * @type {Function} -* @param {PositiveNumber} lambda - mean parameter -* @throws {TypeError} must provide a positive number +* @param {PositiveNumber} lambda - mean * @returns {NonNegativeInteger} pseudorandom number * * @example * var v = poisson( 0.5 ); * // returns +* +* @example +* var v = poisson( 0.0 ); +* // returns NaN +* +* @example +* var v = poisson( NaN ); +* // returns NaN */ var poisson = factory(); diff --git a/lib/node_modules/@stdlib/math/base/random/poisson/lib/rejection.js b/lib/node_modules/@stdlib/math/base/random/poisson/lib/rejection.js new file mode 100644 index 000000000000..9c089999cf71 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/random/poisson/lib/rejection.js @@ -0,0 +1,104 @@ +'use strict'; + +// MODULES // + +var factorialln = require( '@stdlib/math/base/special/factorialln' ); +var floor = require( '@stdlib/math/base/special/floor' ); +var sign = require( '@stdlib/math/base/special/signum' ); +var sqrt = require( '@stdlib/math/base/special/sqrt' ); +var abs = require( '@stdlib/math/base/special/abs' ); +var ln = require( '@stdlib/math/base/special/ln' ); +var LN_SQRT_TWO_PI = require( '@stdlib/math/constants/float64-ln-sqrt-two-pi' ); + + +// VARIABLES // + +var ONE_12 = 1.0 / 12.0; +var ONE_360 = 1.0 / 360.0; + + +// MAIN // + +/** +* Returns a pseudorandom number drawn from a Poisson distribution with parameter `lambda`. +* +* #### References +* +* * Hörmann, W. 1993. "The transformed rejection method for generating Poisson random variables." *Insurance: Mathematics and Economics* 12 (1): 39–45. doi:[10.1016/0167-6687(93)90997-4][@hormann:1993b]. +* +* [@hormann:1993b]: http://dx.doi.org/10.1016/0167-6687(93)90997-4 +* +* +* @private +* @param {Function} rand - PRNG for generating uniformly distributed numbers +* @param {PositiveNumber} lambda - mean +* @returns {NonNegativeInteger} pseudorandom number +*/ +function poisson( rand, lambda ) { + var slambda; + var ainv; + var urvr; + var us; + var vr; + var a; + var b; + var k; + var u; + var v; + + slambda = sqrt( lambda ); + + b = 2.53*slambda + 0.931; + a = 0.02483*b - 0.059; + + ainv = 1.1328/( b-3.4 ) + 1.1239; + vr = -3.6224/( b-2.0 ) + 0.9277; + urvr = 0.86 * vr; + + while ( true ) { + v = rand(); + if ( v <= urvr ) { + u = v / vr - 0.43; + u *= 2.0*a / (0.5-abs(u)) + b; + u += lambda + 0.445; + return floor( u ); + } + if ( v >= vr ) { + u = rand() - 0.5; + } else { + u = v / vr - 0.93; + u = sign( u )*0.5 - u; + v = vr * rand(); + } + us = 0.5 - abs( u ); + if ( + us >= 0.013 || + us >= v + ) { + k = floor( (2.0*a/us + b)*u + lambda + 0.445 ); + v *= ainv / (a/(us*us) + b); + u = (k+0.5) * ln( lambda/k ); + u += -lambda - LN_SQRT_TWO_PI + k; + u -= (ONE_12 - ONE_360/(k*k)) / k; + if ( + k >= 10 && + u >= ln( v*slambda ) + ) { + return k; + } + u = k*ln( lambda ) - lambda - factorialln( k ); + if ( + k >= 0 && + k <= 9 && + u >= ln( v ) + ) { + return k; + } + } + } +} // end FUNCTION poisson() + + +// EXPORTS // + +module.exports = poisson; diff --git a/lib/node_modules/@stdlib/math/base/random/poisson/package.json b/lib/node_modules/@stdlib/math/base/random/poisson/package.json index 5f538d351b22..e8a4d4f41bce 100644 --- a/lib/node_modules/@stdlib/math/base/random/poisson/package.json +++ b/lib/node_modules/@stdlib/math/base/random/poisson/package.json @@ -15,10 +15,13 @@ "statistics", "stats", "prng", + "rng", "pseudorandom", "random", "rand", "randn", + "rpois", + "poisrand", "poisson", "counts", "generator", diff --git a/lib/node_modules/@stdlib/math/base/random/poisson/test/test.factory.js b/lib/node_modules/@stdlib/math/base/random/poisson/test/test.factory.js index 0294b1b360bf..872d8ecd57ce 100644 --- a/lib/node_modules/@stdlib/math/base/random/poisson/test/test.factory.js +++ b/lib/node_modules/@stdlib/math/base/random/poisson/test/test.factory.js @@ -3,10 +3,20 @@ // MODULES // var tape = require( 'tape' ); +var chi2gof = require( '@stdlib/math/generics/statistics/chi2gof' ); var round = require( '@stdlib/math/base/special/round' ); +var isnan = require( '@stdlib/math/base/utils/is-nan' ); +var pmf = require( '@stdlib/math/base/dist/poisson/pmf' ).factory; var factory = require( './../lib/factory.js' ); +// VARIABLES // + +var opts = { + 'skip': ( process.env.TEST_MODE === 'coverage' ) +}; + + // TESTS // tape( 'main export is a function', function test( t ) { @@ -70,6 +80,12 @@ tape( 'attached to the returned function is the generator name', function test( t.end(); }); +tape( 'attached to the returned function is the underlying PRNG', function test( t ) { + var poisson = factory(); + t.equal( typeof poisson.PRNG, 'function', 'has `PRNG` property' ); + t.end(); +}); + tape( 'attached to the returned function is the generator seed', function test( t ) { var poisson = factory({ 'seed': 12345 @@ -79,7 +95,7 @@ tape( 'attached to the returned function is the generator seed', function test( t.end(); }); -tape( 'the function throws an error if the `lambda` value is not a positive number value', function test( t ) { +tape( 'the function throws an error if provided a mean which is not a positive number (no options)', function test( t ) { var values; var i; @@ -107,12 +123,14 @@ tape( 'the function throws an error if the `lambda` value is not a positive numb } }); -tape( 'the function throws an error if the `options` is not a simple object (when `lambda` is not supplied)', function test( t ) { +tape( 'the function throws an error if provided a mean which is not a positive number (options)', function test( t ) { var values; var i; values = [ - 'abc', + -2.0, + 0.0, + '5', null, true, undefined, @@ -128,18 +146,17 @@ tape( 'the function throws an error if the `options` is not a simple object (whe function badValue( value ) { return function() { - factory( value ); + factory( value, {} ); }; } }); -tape( 'the function throws an error if the `options` is not a simple object (when `lambda` is supplied)', function test( t ) { +tape( 'the function throws an error if provided an options argument which is not object (no other arguments)', function test( t ) { var values; var i; values = [ 'abc', - 5, null, true, undefined, @@ -155,27 +172,23 @@ tape( 'the function throws an error if the `options` is not a simple object (whe function badValue( value ) { return function() { - factory( 10.0, value ); + factory( value ); }; } }); -tape( 'when called without parameters, the function returns a generator that throws an error if the `lambda` value is not a positive number', function test( t ) { - var poisson; +tape( 'the function throws an error if provided an options argument which is not an object (other arguments)', function test( t ) { var values; var i; - poisson = factory(); values = [ - -2.0, - 0.0, - '5', + 'abc', + 5, null, true, undefined, NaN, [], - {}, function(){} ]; @@ -186,7 +199,142 @@ tape( 'when called without parameters, the function returns a generator that thr function badValue( value ) { return function() { - poisson( value ); + factory( 10.0, value ); }; } }); + +tape( 'when called without arguments, the function returns a PRNG that returns `NaN` when provided a mean equal to `NaN`', function test( t ) { + var poisson; + var r; + + poisson = factory(); + r = poisson( NaN ); + + t.strictEqual( isnan( r ), true, 'returns NaN' ); + t.end(); +}); + +tape( 'when called without arguments, the function returns a PRNG that returns `NaN` when provided a mean which is not a positive number', function test( t ) { + var poisson; + var r; + + poisson = factory(); + + r = poisson( 0 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + r = poisson( -1 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + r = poisson( -3.14 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + t.end(); +}); + +tape( 'the function returns a PRNG for generating random numbers from a Poisson distribution (lambda < 30)', opts, function test( t ) { + var rejected; + var repeats; + var poisson; + var lambda; + var pValue; + var probs; + var freq; + var ppmf; + var N; + var i; + var j; + var x; + + lambda = 0.73; + ppmf = pmf( lambda ); + + freq = new Array( 30 ); + probs = new Array( freq.length ); + for ( j = 0; j < freq.length; j++ ) { + probs[ j ] = ppmf( j ); + } + repeats = 200; + N = 1e3; + rejected = 0; + for ( i = 0; i < repeats; i++ ) { + poisson = factory( lambda ); + t.ok( true, 'seed: '+poisson.SEED ); + + // Reset the `freq` array... + for ( j = 0; j < freq.length; j++ ) { + freq[ j ] = 0; + } + for ( j = 0; j < N; j++ ) { + x = poisson(); + freq[ x ] += 1; + } + // Test using chi-square goodness-of-fit test: + pValue = chi2gof( freq, probs, { + 'rescale': true, + 'simulate': true, + 'iterations': 500 + }).pValue; + t.equal( typeof pValue, 'number', 'returns a p-value: '+pValue ); + if ( pValue < 0.05 ) { + rejected += 1; + } + } + // Account for small sample sizes and few repeats... + t.ok( rejected / repeats < 0.12, 'null hypothesis (i.e., that numbers are drawn from Poisson('+lambda+') is rejected in less than 12% of cases ('+rejected+' of '+repeats+')' ); + t.end(); +}); + +tape( 'the function returns a PRNG for generating random numbers from a Poisson distribution (lambda > 30)', opts, function test( t ) { + var rejected; + var repeats; + var poisson; + var lambda; + var pValue; + var probs; + var freq; + var ppmf; + var N; + var i; + var j; + var x; + + lambda = 35.7; + ppmf = pmf( lambda ); + + freq = new Array( 300 ); + probs = new Array( freq.length ); + for ( j = 0; j < freq.length; j++ ) { + probs[ j ] = ppmf( j ); + } + repeats = 100; + N = 1e3; + rejected = 0; + for ( i = 0; i < repeats; i++ ) { + poisson = factory( lambda ); + t.ok( true, 'seed: '+poisson.SEED ); + + // Reset the `freq` array... + for ( j = 0; j < freq.length; j++ ) { + freq[ j ] = 0; + } + for ( j = 0; j < N; j++ ) { + x = poisson(); + freq[ x ] += 1; + } + // Test using chi-square goodness-of-fit test: + pValue = chi2gof( freq, probs, { + 'rescale': true, + 'simulate': true, + 'iterations': 500 + }).pValue; + t.equal( typeof pValue, 'number', 'returns a p-value: '+pValue ); + if ( pValue < 0.05 ) { + rejected += 1; + } + } + // Account for small sample sizes and few repeats... + t.ok( rejected / repeats < 0.12, 'null hypothesis (i.e., that numbers are drawn from Poisson('+lambda+') is rejected in less than 12% of cases ('+rejected+' of '+repeats+')' ); + t.end(); +}); diff --git a/lib/node_modules/@stdlib/math/base/random/poisson/test/test.js b/lib/node_modules/@stdlib/math/base/random/poisson/test/test.js index 46f1cf5cb903..210fb0d7c190 100644 --- a/lib/node_modules/@stdlib/math/base/random/poisson/test/test.js +++ b/lib/node_modules/@stdlib/math/base/random/poisson/test/test.js @@ -3,6 +3,8 @@ // MODULES // var tape = require( 'tape' ); +var isNonNegativeInteger = require( '@stdlib/math/base/utils/is-nonnegative-integer' ); +var uniform = require( '@stdlib/math/base/random/uniform' ).factory; var poisson = require( './../lib' ); @@ -24,17 +26,25 @@ tape( 'attached to the main export is the generator name', function test( t ) { t.end(); }); +tape( 'attached to the main export is the underlying PRNG', function test( t ) { + t.equal( typeof poisson.PRNG, 'function', 'has `PRNG` property' ); + t.end(); +}); + tape( 'attached to the main export is the generator seed', function test( t ) { t.equal( typeof poisson.SEED, 'number', 'has `SEED` property' ); t.end(); }); tape( 'the function returns pseudorandom numbers', function test( t ) { + var randu; var r; var i; - for ( i = 0; i < 1e2; i++ ) { - r = poisson( 60.0 ); - t.equal( typeof r, 'number', 'returns a number' ); + + randu = uniform( 0.00000001, 10000.0 ); + for ( i = 0; i < 1e3; i++ ) { + r = poisson( randu() ); + t.strictEqual( isNonNegativeInteger( r ), true, 'returns a nonnegative integer' ); } t.end(); }); diff --git a/lib/node_modules/@stdlib/math/base/random/poisson/test/test.rejection.js b/lib/node_modules/@stdlib/math/base/random/poisson/test/test.rejection.js new file mode 100644 index 000000000000..adda62422c37 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/random/poisson/test/test.rejection.js @@ -0,0 +1,36 @@ +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var randu = require( '@stdlib/math/base/random/randu' ).factory; +var isNonNegativeInteger = require( '@stdlib/math/base/utils/is-nonnegative-integer' ); +var poisson = require( './../lib/rejection.js' ); + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.equal( typeof poisson, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function returns Poisson distributed pseudorandom numbers', function test( t ) { + var lambda; + var rand; + var r; + var i; + + rand = randu({ + 'name': 'minstd-shuffle', + 'seed': 12345 + }); + for ( i = 0; i < 1e4; i++ ) { + // Note: `10.0` is chosen to ensure all code paths are hit. + lambda = rand() + 10.0; + r = poisson( rand, lambda ); + t.strictEqual( isNonNegativeInteger( r ), true, 'returns a nonnegative integer' ); + } + t.end(); +}); diff --git a/lib/node_modules/@stdlib/math/base/random/rayleigh/README.md b/lib/node_modules/@stdlib/math/base/random/rayleigh/README.md index c7b4450a0749..5cd83c0b5597 100644 --- a/lib/node_modules/@stdlib/math/base/random/rayleigh/README.md +++ b/lib/node_modules/@stdlib/math/base/random/rayleigh/README.md @@ -20,32 +20,51 @@ var r = rayleigh( 2.5 ); // returns ``` -If provided `sigma <= 0`, the function throws an error. +If `sigma <= 0` or `sigma` is `NaN`, the function returns `NaN`. ``` javascript var r = rayleigh( -2.0 ); -// throws TypeError +// returns NaN -r = rayleigh( 0.0 ); -// throws TypeError +r = rayleigh( NaN ); +// returns NaN ``` #### rayleigh.factory( \[sigma, \]\[options\] ) -Returns a pseudorandom number generator (PRNG) for generating pseudorandom numbers drawn from a [Rayleigh][rayleigh] distribution. If the scale parameter `sigma` is supplied, the returned generator returns random variates from the specified distribution, otherwise the parameter has to be supplied at each generator invocation. +Returns a pseudorandom number generator (PRNG) for generating pseudorandom numbers drawn from a [Rayleigh][rayleigh] distribution. ``` javascript -// Draw from Rayleigh(5) distribution: var rand = rayleigh.factory(); + var r = rand( 5.0 ); // returns +``` + +If provided `sigma`, the returned generator returns random variates from the specified distribution. + +``` javascript +var rand = rayleigh.factory( 10.0 ); + +var r = rand(); +// returns -// Draw from Rayleigh(10) distribution: -rand = rayleigh.factory( 10.0 ); r = rand(); // returns ``` +If not provided `sigma`, the returned generator requires that `sigma` be provided at each invocation. + +``` javascript +var rand = rayleigh.factory(); + +var r = rand( 4.0 ); +// returns + +r = rand( 3.14 ); +// returns +``` + The function accepts the following `options`: * __seed__: pseudorandom number generator seed. @@ -77,6 +96,15 @@ var name = rayleigh.NAME; // returns 'rayleigh' ``` +#### rayleigh.PRNG + +The underlying pseudorandom number generator. + +``` javascript +var prng = rayleigh.PRNG; +// returns +``` + #### rayleigh.SEED The value used to seed `rayleigh()`. diff --git a/lib/node_modules/@stdlib/math/base/random/rayleigh/lib/_rayleigh.js b/lib/node_modules/@stdlib/math/base/random/rayleigh/lib/_rayleigh.js new file mode 100644 index 000000000000..c5fcf9f7742d --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/random/rayleigh/lib/_rayleigh.js @@ -0,0 +1,26 @@ +'use strict'; + +// MODULES // + +var sqrt = require( '@stdlib/math/base/special/sqrt' ); +var ln = require( '@stdlib/math/base/special/ln' ); + + +// MAIN // + +/** +* Returns a pseudorandom number from a Rayleigh distribution with scale parameter `sigma`. +* +* @private +* @param {Function} rand - PRNG for generating uniformly distributed numbers +* @param {PositiveNumber} sigma - scale parameter +* @returns {NonNegativeNumber} pseudorandom number +*/ +function rayleigh( rand, sigma ) { + return sigma * sqrt( -2.0*ln( rand() ) ); +} // end FUNCTION rayleigh() + + +// EXPORTS // + +module.exports = rayleigh; diff --git a/lib/node_modules/@stdlib/math/base/random/rayleigh/lib/factory.js b/lib/node_modules/@stdlib/math/base/random/rayleigh/lib/factory.js index 0e2a19e5321c..57891ac6d2c0 100644 --- a/lib/node_modules/@stdlib/math/base/random/rayleigh/lib/factory.js +++ b/lib/node_modules/@stdlib/math/base/random/rayleigh/lib/factory.js @@ -5,12 +5,12 @@ var setReadOnly = require( '@stdlib/utils/define-read-only-property' ); var isPositive = require( '@stdlib/utils/is-positive-number' ).isPrimitive; var isObject = require( '@stdlib/utils/is-plain-object' ); -var randu = require( '@stdlib/math/base/random/randu' ); -var sqrt = require( '@stdlib/math/base/special/sqrt' ); -var ln = require( '@stdlib/math/base/special/ln' ); +var randu = require( '@stdlib/math/base/random/randu' ).factory; +var isnan = require( '@stdlib/math/base/utils/is-nan' ); +var rayleigh0 = require( './_rayleigh.js' ); -// FACTORY // +// MAIN // /** * Returns a pseudorandom number generator for generating Rayleigh distributed random numbers. @@ -18,8 +18,8 @@ var ln = require( '@stdlib/math/base/special/ln' ); * @param {PositiveNumber} [sigma] - scale parameter * @param {Options} [options] - function options * @param {*} [options.seed] - pseudorandom number generator seed -* @throws {TypeError} sigma argument must be a positive number -* @throws {TypeError} options must be an object +* @throws {TypeError} `sigma` must be a positive number +* @throws {TypeError} options argument must be an object * @returns {Function} pseudorandom number generator * * @example @@ -33,51 +33,50 @@ var ln = require( '@stdlib/math/base/special/ln' ); * }); * var v = rayleigh(); * // returns +* +* @example +* var rayleigh = factory() +* var v = rayleigh( 0.5 ); +* // returns */ function factory() { - var nargs; var sigma; - var args; var opts; var rand; - var ret; + var prng; - args = arguments; - nargs = args.length; - if ( nargs === 0 ) { - rand = randu.factory(); - } - else { - if ( isObject( args[ 0 ] ) ) { - opts = args[ 0 ]; - rand = randu.factory( opts ); - } else { - sigma = args[ 0 ]; - if ( !isPositive( sigma ) ) { - throw new TypeError( 'invalid input argument. First argument `sigma` must be a positive number. Value: `' + sigma + '`.' ); - } - if ( nargs > 1 ) { - opts = args[ 1 ]; - if ( !isObject( opts ) ) { - throw new TypeError( 'invalid input argument. If supplied, third argument must be an options object. Value: `' + opts + '`.' ); - } - rand = randu.factory( opts ); - } else { - rand = randu.factory(); + if ( arguments.length === 0 ) { + rand = randu(); + } else if ( + arguments.length === 1 && + isObject( arguments[ 0 ] ) + ) { + rand = randu( arguments[ 0 ] ); + } else { + sigma = arguments[ 0 ]; + if ( !isPositive( sigma ) ) { + throw new TypeError( 'invalid input argument. First argument must be a positive number. Value: `' + sigma + '`.' ); + } + if ( arguments.length > 1 ) { + opts = arguments[ 1 ]; + if ( !isObject( opts ) ) { + throw new TypeError( 'invalid input argument. Options argument must be an object. Value: `' + opts + '`.' ); } + rand = randu( opts ); + } else { + rand = randu(); } } - - if ( sigma !== void 0 ) { - ret = rayleigh1; - } - else { - ret = rayleigh2; + if ( sigma === void 0 ) { + prng = rayleigh2; + } else { + prng = rayleigh1; } - setReadOnly( ret, 'NAME', 'rayleigh' ); - setReadOnly( ret, 'SEED', rand.SEED ); - setReadOnly( ret, 'PRNG', rand ); - return ret; + setReadOnly( prng, 'NAME', 'rayleigh' ); + setReadOnly( prng, 'SEED', rand.SEED ); + setReadOnly( prng, 'PRNG', rand ); + + return prng; /** * Returns a pseudorandom number from a Rayleigh distribution with bound scale parameter `sigma`. @@ -90,8 +89,7 @@ function factory() { * // returns */ function rayleigh1() { - var u = rand(); - return sigma * sqrt( -2.0 * ln( u ) ); + return rayleigh0( rand, sigma ); } // end FUNCTION rayleigh1() /** @@ -99,7 +97,6 @@ function factory() { * * @private * @param {PositiveNumber} sigma - scale parameter - * @throws {TypeError} sigma argument must be a positive number * @returns {NonNegativeNumber} pseudorandom number * * @example @@ -107,14 +104,14 @@ function factory() { * // returns */ function rayleigh2( sigma ) { - var u; - if ( !isPositive( sigma ) ) { - throw new TypeError( 'invalid input argument. First argument `sigma` must be a positive number. Value: `' + sigma + '`.' ); + if ( + isnan( sigma ) || + sigma <= 0.0 + ) { + return NaN; } - u = rand(); - return sigma * sqrt( -2.0 * ln( u ) ); + return rayleigh0( rand, sigma ); } // end FUNCTION rayleigh2() - } // end FUNCTION factory() diff --git a/lib/node_modules/@stdlib/math/base/random/rayleigh/lib/rayleigh.js b/lib/node_modules/@stdlib/math/base/random/rayleigh/lib/rayleigh.js index f50cb7b78db3..bda2b2082b41 100644 --- a/lib/node_modules/@stdlib/math/base/random/rayleigh/lib/rayleigh.js +++ b/lib/node_modules/@stdlib/math/base/random/rayleigh/lib/rayleigh.js @@ -5,20 +5,27 @@ var factory = require( './factory.js' ); -// RAYLEIGH PRNG // +// MAIN // /** -* Returns a pseudorandom number from a Rayleigh distribution with scale parameter `sigma`. +* Returns a pseudorandom number drawn from a Rayleigh distribution with scale parameter `sigma`. * -* @function rayleigh +* @name rayleigh * @type {Function} * @param {PositiveNumber} sigma - scale parameter -* @throws {TypeError} sigma argument must be a positive number * @returns {NonNegativeNumber} pseudorandom number * * @example * var v = rayleigh( 3.0 ); * // returns +* +* @example +* var v = rayleigh( 0.0 ); +* // returns NaN +* +* @example +* var v = rayleigh( NaN ); +* // returns NaN */ var rayleigh = factory(); diff --git a/lib/node_modules/@stdlib/math/base/random/rayleigh/package.json b/lib/node_modules/@stdlib/math/base/random/rayleigh/package.json index 4640bf489f42..97f857ebf107 100644 --- a/lib/node_modules/@stdlib/math/base/random/rayleigh/package.json +++ b/lib/node_modules/@stdlib/math/base/random/rayleigh/package.json @@ -15,10 +15,14 @@ "statistics", "stats", "prng", + "rng", "pseudorandom", "random", "rand", "rayleigh", + "continuous", + "distribution", + "dist", "generator", "seed", "seedable", diff --git a/lib/node_modules/@stdlib/math/base/random/rayleigh/test/test.factory.js b/lib/node_modules/@stdlib/math/base/random/rayleigh/test/test.factory.js index a73c35d8a53b..d74ddd0513b1 100644 --- a/lib/node_modules/@stdlib/math/base/random/rayleigh/test/test.factory.js +++ b/lib/node_modules/@stdlib/math/base/random/rayleigh/test/test.factory.js @@ -5,9 +5,17 @@ var tape = require( 'tape' ); var kstest = require( '@stdlib/math/generics/statistics/kstest' ); var round = require( '@stdlib/math/base/special/round' ); +var isnan = require( '@stdlib/math/base/utils/is-nan' ); var factory = require( './../lib/factory.js' ); +// VARIABLES // + +var opts = { + 'skip': ( process.env.TEST_MODE === 'coverage' ) +}; + + // TESTS // tape( 'main export is a function', function test( t ) { @@ -71,6 +79,12 @@ tape( 'attached to the returned function is the generator name', function test( t.end(); }); +tape( 'attached to the returned function is the underlying PRNG', function test( t ) { + var rayleigh = factory(); + t.equal( typeof rayleigh.PRNG, 'function', 'has `PRNG` property' ); + t.end(); +}); + tape( 'attached to the returned function is the generator seed', function test( t ) { var rayleigh = factory({ 'seed': 12345 @@ -80,7 +94,7 @@ tape( 'attached to the returned function is the generator seed', function test( t.end(); }); -tape( 'the function throws an error if the `sigma` value is not a positive number value', function test( t ) { +tape( 'the function throws an error if provided a scale parameter which is not a positive number (no options)', function test( t ) { var values; var i; @@ -108,17 +122,20 @@ tape( 'the function throws an error if the `sigma` value is not a positive numbe } }); -tape( 'the function throws an error if the `options` is not a simple object (when `lambda` is not supplied)', function test( t ) { +tape( 'the function throws an error if provided a scale parameter which is not a positive number (options)', function test( t ) { var values; var i; values = [ - 'abc', + -2.0, + 0.0, + NaN, + '5', null, true, undefined, - NaN, [], + {}, function(){} ]; @@ -129,18 +146,17 @@ tape( 'the function throws an error if the `options` is not a simple object (whe function badValue( value ) { return function() { - factory( value ); + factory( value, {} ); }; } }); -tape( 'the function throws an error if the `options` is not a simple object (when `sigma` is supplied)', function test( t ) { +tape( 'the function throws an error if provided an options argument which is not object (no other arguments)', function test( t ) { var values; var i; values = [ 'abc', - 5, null, true, undefined, @@ -156,27 +172,23 @@ tape( 'the function throws an error if the `options` is not a simple object (whe function badValue( value ) { return function() { - factory( 10.0, value ); + factory( value ); }; } }); -tape( 'when called without parameters, the function returns a generator that throws an error if the `sigma` value is not a positive number', function test( t ) { - var rayleigh; +tape( 'the function throws an error if provided an options argument which is not an object (other arguments)', function test( t ) { var values; var i; - rayleigh = factory(); values = [ - -2.0, - 0.0, - '5', + 'abc', + 5, null, true, undefined, NaN, [], - {}, function(){} ]; @@ -187,40 +199,69 @@ tape( 'when called without parameters, the function returns a generator that thr function badValue( value ) { return function() { - rayleigh( value ); + factory( 10.0, value ); }; } }); -// FIXME // +tape( 'when called without arguments, the function returns a PRNG that returns `NaN` when provided a scale parameter equal to `NaN`', function test( t ) { + var rayleigh; + var r; + + rayleigh = factory(); + r = rayleigh( NaN ); + + t.strictEqual( isnan( r ), true, 'returns NaN' ); + t.end(); +}); -/* -tape( 'the function returns a generator for creating random numbers from the specified Rayleigh distribution', function test( t ) { +tape( 'when called without arguments, the function returns a PRNG that returns `NaN` when provided a scale parameter which is not a positive number', function test( t ) { + var rayleigh; + var r; + + rayleigh = factory(); + + r = rayleigh( 0 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + r = rayleigh( -1 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + r = rayleigh( -3.14 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + t.end(); +}); + +tape( 'the function returns a PRNG for generating random numbers from an Rayleigh distribution', opts, function test( t ) { var rayleigh; var rejected; var pValue; + var sigma; + var N; var i; var j; var x; - rayleigh = factory( 4.0, { - 'seed': 675 - }); + sigma = 4.25; + x = new Array( 1e3 ); rejected = 0; - for ( i = 0; i < 100; i++ ) { - x = new Array( 1e3 ); + N = 300; + for ( i = 0; i < N; i++ ) { + rayleigh = factory( sigma ); + t.ok( true, 'seed: '+rayleigh.SEED ); for ( j = 0; j < x.length; j++ ) { x[ j ] = rayleigh(); } // Test using Kolmogorov-Smirnov goodness-of-fit test: - pValue = kstest( x, 'rayleigh', 4.0 ).pValue; - t.equal( typeof pValue, 'number', 'returns a p-value' ); + pValue = kstest( x, 'rayleigh', sigma ).pValue; + t.equal( typeof pValue, 'number', 'returns a p-value: '+pValue ); if ( pValue < 0.05 ) { rejected += 1; } } - t.ok( rejected / 100 < 0.05, 'null hypothesis (i.e. that numbers are drawn from Rayleigh(4)) is rejected in less than 5% of cases' ); + // Account for small sample sizes and few repeats... + t.ok( rejected / N < 0.10, 'null hypothesis (i.e., that numbers are drawn from Rayleigh('+sigma+') is rejected in less than 10% of cases ('+rejected+' of '+N+')' ); t.end(); }); -*/ diff --git a/lib/node_modules/@stdlib/math/base/random/rayleigh/test/test.js b/lib/node_modules/@stdlib/math/base/random/rayleigh/test/test.js index c674c3c944b0..c631051bcf2e 100644 --- a/lib/node_modules/@stdlib/math/base/random/rayleigh/test/test.js +++ b/lib/node_modules/@stdlib/math/base/random/rayleigh/test/test.js @@ -3,7 +3,6 @@ // MODULES // var tape = require( 'tape' ); -var kstest = require( '@stdlib/math/generics/statistics/kstest' ); var rayleigh = require( './../lib' ); @@ -25,6 +24,11 @@ tape( 'attached to the main export is the generator name', function test( t ) { t.end(); }); +tape( 'attached to the main export is the underlying PRNG', function test( t ) { + t.equal( typeof rayleigh.PRNG, 'function', 'has `PRNG` property' ); + t.end(); +}); + tape( 'attached to the main export is the generator seed', function test( t ) { t.equal( typeof rayleigh.SEED, 'number', 'has `SEED` property' ); t.end(); @@ -34,37 +38,9 @@ tape( 'the function returns pseudorandom numbers', function test( t ) { var r; var i; for ( i = 0; i < 1e2; i++ ) { - r = rayleigh( 3.0 ); - t.equal( typeof r, 'number', 'returns a number' ); - } - t.end(); -}); - -// FIXME // - -/* -tape( 'the function returns pseudorandom numbers from the specified Rayleigh distribution', function test( t ) { - var rejected; - var pValue; - var i; - var j; - var x; - - rejected = 0; - for ( i = 0; i < 300; i++ ) { - x = new Array( 1e3 ); - for ( j = 0; j < x.length; j++ ) { - x[ j ] = rayleigh( 4.0 ); - } - // Test using Kolmogorov-Smirnov goodness-of-fit test: - pValue = kstest( x, 'rayleigh', 4.0 ).pValue; - t.equal( typeof pValue, 'number', 'returns a p-value' ); - if ( pValue <= 0.05 ) { - rejected += 1; - } + r = rayleigh( 3.14 ); + t.strictEqual( typeof r, 'number', 'returns a number' ); + t.strictEqual( r >= 0.0, true, 'returns a positive number' ); } - // Use 0.07 instead of 0.05 as cut-off to accomodate randomly failing tests due to small sample sizes and few iterations... - t.ok( rejected / 300 < 0.07, 'null hypothesis (i.e. that numbers are drawn from Rayleigh(4)) is rejected in less than 7% of cases' ); t.end(); }); -*/ diff --git a/lib/node_modules/@stdlib/math/base/random/t/README.md b/lib/node_modules/@stdlib/math/base/random/t/README.md index 7b7a2a289466..45374f607981 100644 --- a/lib/node_modules/@stdlib/math/base/random/t/README.md +++ b/lib/node_modules/@stdlib/math/base/random/t/README.md @@ -1,6 +1,6 @@ # Student's t Random Numbers -> [Student's t][t] distributed pseudorandom numbers. +> [Student's t][t]-distributed pseudorandom numbers. @@ -13,39 +13,58 @@ var t = require( '@stdlib/math/base/random/t' ); #### t( v ) -Returns a pseudorandom number drawn from a [Student's t][t] distribution with degrees of freedom `v`. +Returns a pseudorandom number drawn from a [Student's t][t]-distribution with degrees of freedom `v`. ``` javascript var r = t( 2.4 ); // returns ``` -If provided `v <= 0`, the function throws an error. +If `v <= 0` or `v` is `NaN`, the function returns `NaN`. ``` javascript var r = t( -2.0 ); -// throws TypeError +// returns NaN -r = t( 0.0 ); -// throws TypeError +r = t( NaN ); +// returns NaN ``` #### t.factory( \[lambda, \]\[options\] ) -Returns a pseudorandom number generator (PRNG) for generating pseudorandom numbers drawn from a [Student's t][t] distribution. If degrees of freedom `v` is supplied, the returned generator returns random variates from the specified distribution, otherwise the parameter has to be supplied at each generator invocation. +Returns a pseudorandom number generator (PRNG) for generating pseudorandom numbers drawn from a [Student's t][t]-distribution. ``` javascript -// Draw from t(5) distribution: var rand = t.factory(); + var r = rand( 5.0 ); // returns +``` + +If provided `v`, the returned generator returns random variates from the specified distribution. + +``` javascript +var rand = t.factory( 1.0 ); + +var r = rand(); +// returns -// Draw from t(1) distribution: -rand = t.factory( 1.0 ); r = rand(); // returns ``` +If not provided `v`, the returned generator requires that `v` be provided at each invocation. + +``` javascript +var rand = t.factory(); + +var r = rand( 4.0 ); +// returns + +r = rand( 3.14 ); +// returns +``` + The function accepts the following `options`: * __seed__: pseudorandom number generator seed. @@ -77,6 +96,15 @@ var name = t.NAME; // returns 't' ``` +#### t.PRNG + +The underlying pseudorandom number generator. + +``` javascript +var prng = t.PRNG; +// returns +``` + #### t.SEED The value used to seed `t()`. diff --git a/lib/node_modules/@stdlib/math/base/random/t/lib/_t.js b/lib/node_modules/@stdlib/math/base/random/t/lib/_t.js new file mode 100644 index 000000000000..5f655e6c792f --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/random/t/lib/_t.js @@ -0,0 +1,26 @@ +'use strict'; + +// MODULES // + +var sqrt = require( '@stdlib/math/base/special/sqrt' ); + + +// MAIN // + +/** +* Returns a pseudorandom number from a Student's t-distribution with degrees of freedom `v`. +* +* @private +* @param {Function} randn - PRNG for generating standard normally distributed numbers +* @param {Function} rchisq - PRNG for generating chi-square distributed numbers +* @param {PositiveNumber} v - degrees of freedom +* @returns {number} pseudorandom number +*/ +function t( randn, rchisq, v ) { + return randn() / sqrt( rchisq( v ) / v ); +} // end FUNCTION t() + + +// EXPORTS // + +module.exports = t; diff --git a/lib/node_modules/@stdlib/math/base/random/t/lib/factory.js b/lib/node_modules/@stdlib/math/base/random/t/lib/factory.js index 21686aaf2aae..c8a361aee5d7 100644 --- a/lib/node_modules/@stdlib/math/base/random/t/lib/factory.js +++ b/lib/node_modules/@stdlib/math/base/random/t/lib/factory.js @@ -3,25 +3,26 @@ // MODULES // var setReadOnly = require( '@stdlib/utils/define-read-only-property' ); +var hasOwnProp = require( '@stdlib/utils/has-own-property' ); var isPositive = require( '@stdlib/utils/is-positive-number' ).isPrimitive; -var chisquare = require( '@stdlib/math/base/random/chisquare' ); var isObject = require( '@stdlib/utils/is-plain-object' ); var minstd = require( '@stdlib/math/base/random/minstd-shuffle' ).factory; -var normal = require( '@stdlib/math/base/random/normal' ); -var randu = require( '@stdlib/math/base/random/randu' ); -var sqrt = require( '@stdlib/math/base/special/sqrt' ); +var chisquare = require( '@stdlib/math/base/random/chisquare' ).factory; +var randn = require( '@stdlib/math/base/random/randn' ).factory; +var isnan = require( '@stdlib/math/base/utils/is-nan' ); +var t0 = require( './_t.js' ); -// FACTORY // +// MAIN // /** -* Returns a pseudorandom number generator for generating t distributed random numbers. +* Returns a pseudorandom number generator for generating t-distributed random numbers. * * @param {PositiveNumber} [v] - degrees of freedom * @param {Options} [options] - function options * @param {*} [options.seed] - pseudorandom number generator seed -* @throws {TypeError} v argument must be a positive number -* @throws {TypeError} options must be an object +* @throws {TypeError} `v` must be a positive number +* @throws {TypeError} options argument must be an object * @returns {Function} pseudorandom number generator * * @example @@ -35,69 +36,61 @@ var sqrt = require( '@stdlib/math/base/special/sqrt' ); * }); * var v = t(); * // returns +* +* @example +* var t = factory() +* var v = t( 0.5 ); +* // returns */ function factory() { - var createRandomInt; var rchisq; - var nargs; + var randi; var rnorm; - var seed1; - var seed2; - var args; var opts; - var rand; - var ret; + var prng; var v; - args = arguments; - nargs = args.length; - if ( nargs === 0 ) { - rand = randu.factory(); - } - else { - if ( isObject( args[ 0 ] ) ) { - opts = args[ 0 ]; - rand = randu.factory( opts ); - } else { - v = args[ 0 ]; - if ( !isPositive( v ) ) { - throw new TypeError( 'invalid input argument. First argument `v` must be a positive number. Value: `' + v + '`.' ); - } - if ( nargs > 1 ) { - opts = args[ 1 ]; - if ( !isObject( opts ) ) { - throw new TypeError( 'invalid input argument. If supplied, third argument must be an options object. Value: `' + opts + '`.' ); - } - rand = randu.factory( opts ); - } else { - rand = randu.factory(); + if ( + arguments.length === 1 && + isObject( arguments[ 0 ] ) + ) { + opts = arguments[ 0 ]; + } else if ( arguments.length > 0 ) { + v = arguments[ 0 ]; + if ( !isPositive( v ) ) { + throw new TypeError( 'invalid input argument. First argument must be a positive number. Value: `' + v + '`.' ); + } + if ( arguments.length > 1 ) { + opts = arguments[ 1 ]; + if ( !isObject( opts ) ) { + throw new TypeError( 'invalid input argument. Options argument must be an object. Value: `' + opts + '`.' ); } } } - - createRandomInt = minstd( rand.SEED ); - seed1 = createRandomInt(); - seed2 = createRandomInt(); - rnorm = normal.factory( 0.0, 1.0, { - 'seed': seed1 + if ( opts && hasOwnProp( opts, 'seed' ) ) { + randi = minstd( opts.seed ); + } else { + randi = minstd(); + } + rnorm = randn({ + 'seed': randi() }); - rchisq = chisquare.factory({ - 'seed': seed2 + rchisq = chisquare({ + 'seed': randi() }); - - if ( v !== void 0 ) { - ret = t1; - } - else { - ret = t2; + if ( v === void 0 ) { + prng = t2; + } else { + prng = t1; } - setReadOnly( ret, 'NAME', 't' ); - setReadOnly( ret, 'SEED', rand.SEED ); - setReadOnly( ret, 'PRNG', rand ); - return ret; + setReadOnly( prng, 'NAME', 't' ); + setReadOnly( prng, 'SEED', randi.SEED ); + setReadOnly( prng, 'PRNG', randi ); + + return prng; /** - * Returns a pseudorandom number from a Student's t distribution with bound degrees of freedom `v`. + * Returns a pseudorandom number drawn from a Student's t-distribution with bound degrees of freedom `v`. * * @private * @returns {number} pseudorandom number @@ -107,28 +100,37 @@ function factory() { * // returns */ function t1() { - return rnorm() / sqrt( rchisq( v ) / v ); + return t0( rnorm, rchisq, v ); } // end FUNCTION t1() /** - * Returns a pseudorandom number from a Student's t distribution with degrees of freedom `v`. + * Returns a pseudorandom number drawn from a Student's t-distribution with degrees of freedom `v`. * * @private * @param {PositiveNumber} v - degrees of freedom - * @throws {TypeError} v argument must be a positive number * @returns {number} pseudorandom number * * @example * var v = t2( 3.0 ); * // returns + * + * @example + * var v = t2( 0.0 ); + * // returns NaN + * + * @example + * var v = t2( -1.5 ); + * // returns NaN */ function t2( v ) { - if ( !isPositive( v ) ) { - throw new TypeError( 'invalid input argument. Degrees of freedom `v` must be a positive number. Value: `' + v + '`.' ); + if ( + isnan( v ) || + v <= 0.0 + ) { + return NaN; } - return rnorm() / sqrt( rchisq( v ) / v ); + return t0( rnorm, rchisq, v ); } // end FUNCTION t2() - } // end FUNCTION factory() diff --git a/lib/node_modules/@stdlib/math/base/random/t/lib/index.js b/lib/node_modules/@stdlib/math/base/random/t/lib/index.js index ad1b004b5c01..50256ffdb063 100644 --- a/lib/node_modules/@stdlib/math/base/random/t/lib/index.js +++ b/lib/node_modules/@stdlib/math/base/random/t/lib/index.js @@ -1,7 +1,7 @@ 'use strict'; /** -* Student's t distributed pseudorandom numbers. +* Student's t-distributed pseudorandom numbers. * * @module @stdlib/math/base/random/t * @@ -14,7 +14,7 @@ * @example * var factory = require( '@stdlib/math/base/random/t' ).factory; * var t = factory( 3.0, { -* 'seed': 297 +* 'seed': 297 * }); * * var v = t(); @@ -23,7 +23,7 @@ * @example * var factory = require( '@stdlib/math/base/random/t' ).factory; * var t = factory({ -* 'seed': 297 +* 'seed': 297 * }); * * var v = t( 2.0 ); diff --git a/lib/node_modules/@stdlib/math/base/random/t/lib/t.js b/lib/node_modules/@stdlib/math/base/random/t/lib/t.js index 09f6e47fd72e..c264a8b15b01 100644 --- a/lib/node_modules/@stdlib/math/base/random/t/lib/t.js +++ b/lib/node_modules/@stdlib/math/base/random/t/lib/t.js @@ -5,20 +5,27 @@ var factory = require( './factory.js' ); -// STUDENT'S T PRNG // +// MAIN // /** -* Returns a pseudorandom number from a Student's t distribution with degrees of freedom `v`. +* Returns a pseudorandom number drawn from a Student's t-distribution with degrees of freedom `v`. * -* @function t +* @name t * @type {Function} * @param {PositiveNumber} v - degrees of freedom -* @throws {TypeError} v argument must be a positive number * @returns {number} pseudorandom number * * @example * var v = t( 3.0 ); * // returns +* +* @example +* var v = t( 0.0 ); +* // returns NaN +* +* @example +* var v = t( NaN ); +* // returns NaN */ var t = factory(); diff --git a/lib/node_modules/@stdlib/math/base/random/t/package.json b/lib/node_modules/@stdlib/math/base/random/t/package.json index 7a0c0da4d1d8..281f6594303d 100644 --- a/lib/node_modules/@stdlib/math/base/random/t/package.json +++ b/lib/node_modules/@stdlib/math/base/random/t/package.json @@ -1,7 +1,7 @@ { "name": "", "version": "", - "description": "Student's t distributed pseudorandom numbers.", + "description": "Student's t-distributed pseudorandom numbers.", "author": {}, "contributors": [], "scripts": {}, @@ -15,12 +15,17 @@ "statistics", "stats", "prng", + "rng", "pseudorandom", "random", "rand", "randn", "normal", "gaussian", + "t", + "student", + "distribution", + "dist", "generator", "seed", "seedable", diff --git a/lib/node_modules/@stdlib/math/base/random/t/test/test.factory.js b/lib/node_modules/@stdlib/math/base/random/t/test/test.factory.js index 159464d8c1b4..d60413e775ca 100644 --- a/lib/node_modules/@stdlib/math/base/random/t/test/test.factory.js +++ b/lib/node_modules/@stdlib/math/base/random/t/test/test.factory.js @@ -5,9 +5,17 @@ var tape = require( 'tape' ); var kstest = require( '@stdlib/math/generics/statistics/kstest' ); var round = require( '@stdlib/math/base/special/round' ); +var isnan = require( '@stdlib/math/base/utils/is-nan' ); var factory = require( './../lib/factory.js' ); +// VARIABLES // + +var opts = { + 'skip': ( process.env.TEST_MODE === 'coverage' ) +}; + + // TESTS // tape( 'main export is a function', function test( t ) { @@ -39,9 +47,9 @@ tape( 'the function returns a pseudorandom number generator (no seed)', function }); tape( 'the function returns a seeded pseudorandom number generator', function test( t ) { + var seed; var rt1; var rt2; - var seed; var r1; var r2; var i; @@ -71,6 +79,12 @@ tape( 'attached to the returned function is the generator name', function test( t.end(); }); +tape( 'attached to the returned function is the underlying PRNG', function test( t ) { + var rt = factory(); + t.equal( typeof rt.PRNG, 'function', 'has `PRNG` property' ); + t.end(); +}); + tape( 'attached to the returned function is the generator seed', function test( t ) { var rt = factory({ 'seed': 12345 @@ -80,7 +94,7 @@ tape( 'attached to the returned function is the generator seed', function test( t.end(); }); -tape( 'the function throws an error if degrees of freedom `v` is not a positive number value', function test( t ) { +tape( 'the function throws an error if provided a degrees of freedom parameter which is not a positive number (no options)', function test( t ) { var values; var i; @@ -108,17 +122,20 @@ tape( 'the function throws an error if degrees of freedom `v` is not a positive } }); -tape( 'the function throws an error if the `options` is not a simple object (when `v` is not supplied)', function test( t ) { +tape( 'the function throws an error if provided a degrees of freedom parameter which is not a positive number (options)', function test( t ) { var values; var i; values = [ - 'abc', + -2.0, + 0.0, + NaN, + '5', null, true, undefined, - NaN, [], + {}, function(){} ]; @@ -129,18 +146,17 @@ tape( 'the function throws an error if the `options` is not a simple object (whe function badValue( value ) { return function() { - factory( value ); + factory( value, {} ); }; } }); -tape( 'the function throws an error if the `options` is not a simple object (when `v` is supplied)', function test( t ) { +tape( 'the function throws an error if provided an options argument which is not object (no other arguments)', function test( t ) { var values; var i; values = [ 'abc', - 5, null, true, undefined, @@ -156,27 +172,23 @@ tape( 'the function throws an error if the `options` is not a simple object (whe function badValue( value ) { return function() { - factory( 10.0, value ); + factory( value ); }; } }); -tape( 'when called without parameters, the function returns a generator that throws an error if degrees of freedom `v` is not a positive number', function test( t ) { +tape( 'the function throws an error if provided an options argument which is not an object (other arguments)', function test( t ) { var values; - var rt; var i; - rt = factory(); values = [ - -2.0, - 0.0, - '5', + 'abc', + 5, null, true, undefined, NaN, [], - {}, function(){} ]; @@ -187,40 +199,69 @@ tape( 'when called without parameters, the function returns a generator that thr function badValue( value ) { return function() { - rt( value ); + factory( 10.0, value ); }; } }); -// FIXME // +tape( 'when called without arguments, the function returns a PRNG that returns `NaN` when provided a degrees of freedom parameter equal to `NaN`', function test( t ) { + var rt; + var r; + + rt = factory(); + r = rt( NaN ); + + t.strictEqual( isnan( r ), true, 'returns NaN' ); + t.end(); +}); + +tape( 'when called without arguments, the function returns a PRNG that returns `NaN` when provided a degrees of freedom parameter which is not a positive number', function test( t ) { + var rt; + var r; + + rt = factory(); + + r = rt( 0 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + r = rt( -1 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); -/* -tape( 'the function returns a generator for creating random numbers from the specified Student's t distribution', function test( t ) { + r = rt( -3.14 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + t.end(); +}); + +tape( 'the function returns a PRNG for generating random numbers from a Student\'s t-distribution', opts, function test( t ) { var rejected; var pValue; var rt; + var N; + var v; var i; var j; var x; - rt = factory( 4.0, { - 'seed': 675 - }); + v = 9.0; + x = new Array( 1e3 ); rejected = 0; - for ( i = 0; i < 100; i++ ) { - x = new Array( 1e3 ); + N = 300; + for ( i = 0; i < N; i++ ) { + rt = factory( v ); + t.ok( true, 'seed: '+rt.SEED ); for ( j = 0; j < x.length; j++ ) { x[ j ] = rt(); } // Test using Kolmogorov-Smirnov goodness-of-fit test: - pValue = kstest( x, 't', 4.0 ).pValue; - t.equal( typeof pValue, 'number', 'returns a p-value' ); + pValue = kstest( x, 't', v ).pValue; + t.equal( typeof pValue, 'number', 'returns a p-value: '+pValue ); if ( pValue < 0.05 ) { rejected += 1; } } - t.ok( rejected / 100 < 0.05, 'null hypothesis (i.e. that numbers are drawn from t(4)) is rejected in less than 5% of cases' ); + // Account for small sample sizes and few repeats... + t.ok( rejected / N < 0.10, 'null hypothesis (i.e., that numbers are drawn from T('+v+') is rejected in less than 10% of cases ('+rejected+' of '+N+')' ); t.end(); }); -*/ diff --git a/lib/node_modules/@stdlib/math/base/random/t/test/test.js b/lib/node_modules/@stdlib/math/base/random/t/test/test.js index 9264b050b225..4a2d8c91b8d1 100644 --- a/lib/node_modules/@stdlib/math/base/random/t/test/test.js +++ b/lib/node_modules/@stdlib/math/base/random/t/test/test.js @@ -3,7 +3,6 @@ // MODULES // var tape = require( 'tape' ); -var kstest = require( '@stdlib/math/generics/statistics/kstest' ); var rt = require( './../lib' ); @@ -25,6 +24,11 @@ tape( 'attached to the main export is the generator name', function test( t ) { t.end(); }); +tape( 'attached to the main export is the underlying PRNG', function test( t ) { + t.equal( typeof rt.PRNG, 'function', 'has `PRNG` property' ); + t.end(); +}); + tape( 'attached to the main export is the generator seed', function test( t ) { t.equal( typeof rt.SEED, 'number', 'has `SEED` property' ); t.end(); @@ -35,36 +39,7 @@ tape( 'the function returns pseudorandom numbers', function test( t ) { var i; for ( i = 0; i < 1e2; i++ ) { r = rt( 3.0 ); - t.equal( typeof r, 'number', 'returns a number' ); - } - t.end(); -}); - -// FIXME // - -/* -tape( 'the function returns pseudorandom numbers from the specified Student's t distribution', function test( t ) { - var rejected; - var pValue; - var i; - var j; - var x; - - rejected = 0; - for ( i = 0; i < 300; i++ ) { - x = new Array( 1e3 ); - for ( j = 0; j < x.length; j++ ) { - x[ j ] = rt( 4.0 ); - } - // Test using Kolmogorov-Smirnov goodness-of-fit test: - pValue = kstest( x, 't', 4.0 ).pValue; - t.equal( typeof pValue, 'number', 'returns a p-value' ); - if ( pValue <= 0.05 ) { - rejected += 1; - } + t.strictEqual( typeof r, 'number', 'returns a number' ); } - // Use 0.07 instead of 0.05 as cut-off to accomodate randomly failing tests due to small sample sizes and few iterations... - t.ok( rejected / 300 < 0.07, 'null hypothesis (i.e. that numbers are drawn from t(4)) is rejected in less than 7% of cases' ); t.end(); }); -*/ diff --git a/lib/node_modules/@stdlib/math/base/random/triangular/README.md b/lib/node_modules/@stdlib/math/base/random/triangular/README.md index e67857b9b8c9..5e3ea802af0d 100644 --- a/lib/node_modules/@stdlib/math/base/random/triangular/README.md +++ b/lib/node_modules/@stdlib/math/base/random/triangular/README.md @@ -13,37 +13,68 @@ var triangular = require( '@stdlib/math/base/random/triangular' ); #### triangular( a, b, c ) -Returns a pseudorandom number drawn from a [triangular][triangular] distribution with parameters `a` (minimum support), `b` (maximum support) and `c` (mode). +Returns a pseudorandom number drawn from a [triangular][triangular] distribution with parameters `a` (minimum support), `b` (maximum support), and `c` (mode). ``` javascript -var r = triangular( 2.0, 5.0 ); +var r = triangular( 2.0, 5.0, 3.33 ); // returns ``` -If provided parameters not satisfying `a <= c <= b`, the function throws an error. +If either `a`, `b`, or `c` is `NaN`, the function returns `NaN`. ``` javascript -var r = triangular( 2.0, 1.0, 1.5 ); -// throws RangeError +var r = triangular( NaN, 1.0, 0.5 ); +// returns NaN -r = triangular( 1.0, 2.0, 3.0 ); -// throws RangeError +r = triangular( 1.0, NaN, 2.42 ); +// returns NaN + +r = triangular( 1.0, 10.0, NaN ); +// returns NaN +``` + +If the condition `a <= c <= b` is not satisfied, the function returns `NaN`. + +``` javascript +var r = triangular( 13.0, 9.0, 0.5 ); +// returns NaN ``` #### triangular.factory( \[a, b, c, \]\[options\] ) -Returns a pseudorandom number generator (PRNG) for generating pseudorandom numbers drawn from a [triangular][triangular] distribution. If `a` (minimum support), `b` (maximum support) and `c` (mode) are supplied, the returned generator returns random variates from the specified distribution, otherwise the parameters have to be supplied at each generator invocation. +Returns a pseudorandom number generator (PRNG) for generating pseudorandom numbers drawn from a [triangular][triangular] distribution. ``` javascript var rand = triangular.factory(); + var r = rand( 0.0, 1.0, 0.5 ); // returns +``` + +If provided `a`, `b`, and `c`, the returned generator returns random variates from the specified distribution. + +``` javascript +var rand = triangular.factory( -2.0, 2.0, 1.0 ); + +var r = rand(); +// returns -rand = triangular.factory( -2.0, 2.0, 1.0 ); r = rand(); // returns ``` +If not provided `a`, `b`, and `c`, the returned generator requires that all three parameters be provided at each invocation. + +``` javascript +var rand = triangular.factory(); + +var r = rand( 0.0, 1.0, 0.75 ); +// returns + +r = rand( -2.0, 2.0, 0.1 ); +// returns +``` + The function accepts the following `options`: * __seed__: pseudorandom number generator seed. @@ -75,6 +106,15 @@ var name = triangular.NAME; // returns 'triangular' ``` +#### triangular.PRNG + +The underlying pseudorandom number generator. + +``` javascript +var prng = triangular.PRNG; +// returns +``` + #### triangular.SEED The value used to seed `triangular()`. diff --git a/lib/node_modules/@stdlib/math/base/random/triangular/lib/_triangular.js b/lib/node_modules/@stdlib/math/base/random/triangular/lib/_triangular.js new file mode 100644 index 000000000000..16e4b01ee425 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/random/triangular/lib/_triangular.js @@ -0,0 +1,37 @@ +'use strict'; + +// MODULES // + +var sqrt = require( '@stdlib/math/base/special/sqrt' ); + + +// MAIN // + +/* +* Returns a pseudorandom number drawn from a triangular distribution with minimum support `a`, maximum support `b` and mode `c`. +* +* @private +* @param {Function} rand - PRNG for generating uniformly distributed numbers +* @param {number} a - minimum support +* @param {number} b - maximum support +* @param {number} c - mode +* @returns {number} pseudorandom number +*/ +function triangular( rand, a, b, c ) { + var fc; + var x; + var u; + fc = (c - a) / (b - a); + u = rand(); + if ( u < fc ) { + x = (b - a) * (c - a); + return a + sqrt( x * u ); + } + x = (b - a) * (b - c); + return b - sqrt( x * (1.0 - u) ); +} // end FUNCTION triangular() + + +// EXPORTS // + +module.exports = triangular; diff --git a/lib/node_modules/@stdlib/math/base/random/triangular/lib/factory.js b/lib/node_modules/@stdlib/math/base/random/triangular/lib/factory.js index ba572fd2d173..32986253cfb7 100644 --- a/lib/node_modules/@stdlib/math/base/random/triangular/lib/factory.js +++ b/lib/node_modules/@stdlib/math/base/random/triangular/lib/factory.js @@ -3,28 +3,28 @@ // MODULES // var setReadOnly = require( '@stdlib/utils/define-read-only-property' ); -var isNumber = require( '@stdlib/utils/is-number' ).isPrimitive; var isObject = require( '@stdlib/utils/is-plain-object' ); -var isnan = require( '@stdlib/utils/is-nan' ); -var randu = require( '@stdlib/math/base/random/randu' ); -var sqrt = require( '@stdlib/math/base/special/sqrt' ); +var randu = require( '@stdlib/math/base/random/randu' ).factory; +var isnan = require( '@stdlib/math/base/utils/is-nan' ); +var validate = require( './validate.js' ); +var triangular0 = require( './_triangular.js' ); -// FACTORY // +// MAIN // /** -* Returns a pseudorandom number generator for generating random numbers from a triangular distribution. +* Returns a pseudorandom number generator for generating random numbers drawn from a triangular distribution. * * @param {number} [a] - minimum support * @param {number} [b] - maximum support * @param {number} [c] - mode * @param {Options} [options] - function options * @param {*} [options.seed] - pseudorandom number generator seed -* @throws {TypeError} a argument must be numeric -* @throws {TypeError} b argument must be numeric -* @throws {TypeError} c argument must be numeric -* @throws {RangeError} arguments must satisfy a <= c and c <= b -* @throws {TypeError} options must be an object +* @throws {TypeError} `a` must be a number +* @throws {TypeError} `b` must be a number +* @throws {TypeError} `c` must be a number +* @throws {RangeError} arguments must satisfy `a <= c <= b` +* @throws {TypeError} options argument must be an object * @returns {Function} pseudorandom number generator * * @example @@ -40,64 +40,53 @@ var sqrt = require( '@stdlib/math/base/special/sqrt' ); * // returns ~-2.176 */ function factory() { - var nargs; - var args; var opts; var rand; - var ret; + var prng; + var err; var a; var b; var c; - args = arguments; - nargs = args.length; - if ( nargs === 0 ) { - rand = randu.factory(); - } - else { - if ( isObject( args[ 0 ] ) ) { - opts = args[ 0 ]; - rand = randu.factory( opts ); - } else { - a = args[ 0 ]; - b = args[ 1 ]; - c = args[ 2 ]; - if ( !isNumber( a ) || isnan( a ) ) { - throw new TypeError( 'invalid input argument. `a` must be a number primitive. Value: `' + a + '`.' ); - } - if ( !isNumber( b ) || isnan( b ) ) { - throw new TypeError( 'invalid input argument. `b` must be a number primitive. Value: `' + b + '`.' ); - } - if ( !isNumber( c ) || isnan( c ) ) { - throw new TypeError( 'invalid input argument. `c` must be a number primitive. Value: `' + c + '`.' ); - } - if ( !( a <= c && c <= b ) ) { - throw new RangeError( 'invalid input arguments. The conditions `a <= c` and `c <= b` have to be satisfied.' ); - } - if ( nargs > 3 ) { - opts = args[ 3 ]; - if ( !isObject( opts ) ) { - throw new TypeError( 'invalid input argument. If supplied, third argument must be an options object. Value: `' + opts + '`.' ); - } - rand = randu.factory( opts ); - } else { - rand = randu.factory(); + if ( arguments.length === 0 ) { + rand = randu(); + } else if ( arguments.length === 1 ) { + opts = arguments[ 0 ]; + if ( !isObject( opts ) ) { + throw new TypeError( 'invalid input argument. Options argument must be an object. Value: `'+opts+'`.' ); + } + rand = randu( opts ); + } else { + a = arguments[ 0 ]; + b = arguments[ 1 ]; + c = arguments[ 2 ]; + err = validate( a, b, c ); + if ( err ) { + throw err; + } + if ( arguments.length > 3 ) { + opts = arguments[ 3 ]; + if ( !isObject( opts ) ) { + throw new TypeError( 'invalid input argument. Options argument must be an object. Value: `' + opts + '`.' ); } + rand = randu( opts ); + } else { + rand = randu(); } } - - if ( a !== void 0 ) { - ret = triangular1; + if ( a === void 0 ) { + prng = triangular2; } else { - ret = triangular2; + prng = triangular1; } - setReadOnly( ret, 'NAME', 'triangular' ); - setReadOnly( ret, 'SEED', rand.SEED ); - setReadOnly( ret, 'PRNG', rand ); - return ret; + setReadOnly( prng, 'NAME', 'triangular' ); + setReadOnly( prng, 'SEED', rand.SEED ); + setReadOnly( prng, 'PRNG', rand ); + + return prng; /* - * Returns a pseudorandom number from a triangular distribution with bound parameters. + * Returns a pseudorandom number drawn from a triangular distribution with bound parameters. * * @private * @returns {number} pseudorandom number @@ -107,71 +96,41 @@ function factory() { * // returns */ function triangular1() { - var pInflection; - var fact1; - var fact2; - var u; - - pInflection = ( c - a ) / ( b - a ); - fact1 = ( b - a ) * ( c - a ); - fact2 = ( b - a ) * ( b - c ); - - u = rand(); - if ( u < pInflection ) { - return a + sqrt( fact1 * u ); - } - // Case: u >= pInflection - return b - sqrt( fact2 * ( 1.0 - u ) ); + return triangular0( rand, a, b, c ); } // end FUNCTION triangular1() /* - * Returns a pseudorandom number from a triangular distribution with minimum support `a`, maximum support `b` and mode `c`. + * Returns a pseudorandom number drawn from a triangular distribution with minimum support `a`, maximum support `b`, and mode `c`. * * @private * @param {number} a - minimum support * @param {number} b - maximum support * @param {number} c - mode - * @throws {TypeError} a argument must be numeric - * @throws {TypeError} b argument must be numeric - * @throws {TypeError} c argument must be numeric - * @throws {RangeError} arguments must satisfy a <= c and c <= b * @returns {number} pseudorandom number * * @example * var v = triangular2( 0.0, 1.0, 0.5 ); * // returns + * + * @example + * var v = triangular2( 1.0, 0.0, 0.5 ); + * // returns NaN + * + * @example + * var v = triangular2( 1.0, 2.0, NaN ); + * // returns NaN */ function triangular2( a, b, c ) { - var pInflection; - var fact1; - var fact2; - var u; - - if ( !isNumber( a ) || isnan( a ) ) { - throw new TypeError( 'invalid input argument. `a` must be a number primitive. Value: `' + a + '`.' ); - } - if ( !isNumber( b ) || isnan( b ) ) { - throw new TypeError( 'invalid input argument. `b` must be a number primitive. Value: `' + b + '`.' ); + if ( + isnan( a ) || + isnan( b ) || + isnan( c ) || + !(a <= c && c <= b) + ) { + return NaN; } - if ( !isNumber( c ) || isnan( c ) ) { - throw new TypeError( 'invalid input argument. `c` must be a number primitive. Value: `' + c + '`.' ); - } - if ( !( a <= c && c <= b ) ) { - throw new RangeError( 'invalid input arguments. The conditions `a <= c` and `c <= b` have to be satisfied.' ); - } - - pInflection = ( c - a ) / ( b - a ); - fact1 = ( b - a ) * ( c - a ); - fact2 = ( b - a ) * ( b - c ); - - u = rand(); - if ( u < pInflection ) { - return a + sqrt( fact1 * u ); - } - // Case: u >= pInflection - return b - sqrt( fact2 * ( 1.0 - u ) ); + return triangular0( rand, a, b, c ); } // end FUNCTION triangular2() - } // end FUNCTION factory() diff --git a/lib/node_modules/@stdlib/math/base/random/triangular/lib/index.js b/lib/node_modules/@stdlib/math/base/random/triangular/lib/index.js index 392efc595104..8383ad90d98b 100644 --- a/lib/node_modules/@stdlib/math/base/random/triangular/lib/index.js +++ b/lib/node_modules/@stdlib/math/base/random/triangular/lib/index.js @@ -1,7 +1,7 @@ 'use strict'; /** -* Triangular distribution pseudorandom numbers. +* Triangular distributed pseudorandom numbers. * * @module @stdlib/math/base/random/triangular * diff --git a/lib/node_modules/@stdlib/math/base/random/triangular/lib/triangular.js b/lib/node_modules/@stdlib/math/base/random/triangular/lib/triangular.js index 894c2095a512..978ce071c2ae 100644 --- a/lib/node_modules/@stdlib/math/base/random/triangular/lib/triangular.js +++ b/lib/node_modules/@stdlib/math/base/random/triangular/lib/triangular.js @@ -5,20 +5,16 @@ var factory = require( './factory.js' ); -// TRIANGULAR PRNG // +// MAIN // /* -* Returns a pseudorandom number from a triangular distribution with minimum support `a`, maximum support `b` and mode `c`. +* Returns a pseudorandom number drawn from a triangular distribution with minimum support `a`, maximum support `b`, and mode `c`. * -* @function triangular +* @name triangular * @type {Function} * @param {number} a - minimum support * @param {number} b - maximum support * @param {number} c - mode -* @throws {TypeError} a argument must be numeric -* @throws {TypeError} b argument must be numeric -* @throws {TypeError} c argument must be numeric -* @throws {RangeError} arguments must satisfy a <= c and c <= b * @returns {number} pseudorandom number * * @example diff --git a/lib/node_modules/@stdlib/math/base/random/triangular/lib/validate.js b/lib/node_modules/@stdlib/math/base/random/triangular/lib/validate.js new file mode 100644 index 000000000000..e3ecd7bdaf55 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/random/triangular/lib/validate.js @@ -0,0 +1,45 @@ +'use strict'; + +// MODULES // + +var isNumber = require( '@stdlib/utils/is-number' ).isPrimitive; +var isnan = require( '@stdlib/utils/is-nan' ); + + +// MAIN // + +/** +* Validates parameters. +* +* @private +* @param {number} a - minimum support +* @param {number} b - maximum support +* @param {number} c - mode +* @returns {(Error|null)} error or null +* +* @example +* var err = validate( 1.0, 2.0, 1.3 ); +* if ( err ) { +* throw err; +* } +*/ +function validate( a, b, c ) { + if ( !isNumber( a ) || isnan( a ) ) { + return new TypeError( 'invalid input argument. First argument must be a number primitive and not `NaN`. Value: `'+a+'`.' ); + } + if ( !isNumber( b ) || isnan( b ) ) { + return new TypeError( 'invalid input argument. Second argument must be a number primitive and not `NaN`. Value: `'+b+'`.' ); + } + if ( !isNumber( c ) || isnan( c ) ) { + return new TypeError( 'invalid input argument. Third argument must be a number primitive and not `NaN`. Value: `'+c+'`.' ); + } + if ( !(a <= c && c <= b) ) { + return new RangeError( 'invalid input arguments. The condition `a <= c <= b` must be satisfied. Value: `['+a+','+b+','+c+']`.'); + } + return null; +} // end FUNCTION validate() + + +// EXPORTS // + +module.exports = validate; diff --git a/lib/node_modules/@stdlib/math/base/random/triangular/package.json b/lib/node_modules/@stdlib/math/base/random/triangular/package.json index c5f02284c09a..78fa7c53d6a5 100644 --- a/lib/node_modules/@stdlib/math/base/random/triangular/package.json +++ b/lib/node_modules/@stdlib/math/base/random/triangular/package.json @@ -15,10 +15,14 @@ "statistics", "stats", "prng", + "rng", "pseudorandom", "random", "rand", "triangular", + "continuous", + "distribution", + "dist", "generator", "seed", "seedable", diff --git a/lib/node_modules/@stdlib/math/base/random/triangular/test/test.factory.js b/lib/node_modules/@stdlib/math/base/random/triangular/test/test.factory.js index 3962f8206ce5..513a5d427a52 100644 --- a/lib/node_modules/@stdlib/math/base/random/triangular/test/test.factory.js +++ b/lib/node_modules/@stdlib/math/base/random/triangular/test/test.factory.js @@ -5,9 +5,17 @@ var tape = require( 'tape' ); var kstest = require( '@stdlib/math/generics/statistics/kstest' ); var round = require( '@stdlib/math/base/special/round' ); +var isnan = require( '@stdlib/math/base/utils/is-nan' ); var factory = require( './../lib/factory.js' ); +// VARIABLES // + +var opts = { + 'skip': ( process.env.TEST_MODE === 'coverage' ) +}; + + // TESTS // tape( 'main export is a function', function test( t ) { @@ -71,6 +79,12 @@ tape( 'attached to the returned function is the generator name', function test( t.end(); }); +tape( 'attached to the returned function is the underlying PRNG', function test( t ) { + var triangular = factory(); + t.equal( typeof triangular.PRNG, 'function', 'has `PRNG` property' ); + t.end(); +}); + tape( 'attached to the returned function is the generator seed', function test( t ) { var triangular = factory({ 'seed': 12345 @@ -91,6 +105,7 @@ tape( 'the function throws an error if minimum support `a` is not a number primi undefined, NaN, [], + {}, function(){} ]; @@ -160,7 +175,7 @@ tape( 'the function throws an error if mode `c` is not a number primitive', func } }); -tape( 'the function throws an error if the conditions `a <= c` and `c <= b` are not satisfied', function test( t ) { +tape( 'the function throws an error if the condition `a <= c <= b` is not satisfied', function test( t ) { var values; var i; @@ -182,7 +197,7 @@ tape( 'the function throws an error if the conditions `a <= c` and `c <= b` are } }); -tape( 'the function throws an error if the `options` is not a simple object (when `a`, `b` and `c` are not supplied)', function test( t ) { +tape( 'the function throws an error if provided an options argument which is not an object (no other arguments)', function test( t ) { var values; var i; @@ -209,7 +224,7 @@ tape( 'the function throws an error if the `options` is not a simple object (whe } }); -tape( 'the function throws an error if the `options` is not a simple object (when `a`, `b` and `c` are supplied)', function test( t ) { +tape( 'the function throws an error if provided an options argument which is not an object (other arguments)', function test( t ) { var values; var i; @@ -236,146 +251,106 @@ tape( 'the function throws an error if the `options` is not a simple object (whe } }); -tape( 'when called without parameters, the function returns a generator that throws an error if minimum support `a` value is not a number primitive', function test( t ) { +tape( 'when called without arguments, the function returns a function that returns `NaN` if `a` is `NaN`', function test( t ) { var triangular; - var values; - var i; + var r; triangular = factory(); - values = [ - '5', - null, - true, - undefined, - NaN, - [], - {}, - function(){} - ]; + r = triangular( NaN, 5.0, 2.5 ); - for ( i = 0; i < values.length; i++ ) { - t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] ); - } + t.strictEqual( isnan( r ), true, 'returns NaN' ); t.end(); - - function badValue( value ) { - return function() { - triangular( value, 1.0, 0.5 ); - }; - } }); -tape( 'when called without parameters, the function returns a generator that throws an error if maximum support `b` is not a number primitive', function test( t ) { +tape( 'when called without arguments, the function returns a function that returns `NaN` if `b` is `NaN`', function test( t ) { var triangular; - var values; - var i; + var r; triangular = factory(); - values = [ - '5', - null, - true, - undefined, - NaN, - [], - {}, - function(){} - ]; + r = triangular( 0.0, NaN, 1.0 ); - for ( i = 0; i < values.length; i++ ) { - t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] ); - } + t.strictEqual( isnan( r ), true, 'returns NaN' ); t.end(); - - function badValue( value ) { - return function() { - triangular( 1.0, value, 1.5 ); - }; - } }); -tape( 'when called without parameters, the function returns a generator that throws an error if mode `c` is not a number primitive', function test( t ) { +tape( 'when called without arguments, the function returns a function that returns `NaN` if `c` is `NaN`', function test( t ) { var triangular; - var values; - var i; + var r; triangular = factory(); - values = [ - '5', - null, - true, - undefined, - NaN, - [], - {}, - function(){} - ]; + r = triangular( 0.0, 10.0, NaN ); - for ( i = 0; i < values.length; i++ ) { - t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] ); - } + t.strictEqual( isnan( r ), true, 'returns NaN' ); t.end(); +}); - function badValue( value ) { - return function() { - triangular( 0.0, 1.0, value ); - }; - } +tape( 'when called without arguments, the function returns a function that returns `NaN` if provided all `NaNs`', function test( t ) { + var triangular; + var r; + + triangular = factory(); + r = triangular( NaN, NaN, NaN ); + + t.strictEqual( isnan( r ), true, 'returns NaN' ); + t.end(); }); -tape( 'when called without parameters, the function returns a generator that throws an error if minimum support `a` is not less than maximum support `b`', function test( t ) { +tape( 'when called without arguments, the function returns a function that returns `NaN` if the condition `a <= c <= b` is not satisfied', function test( t ) { var triangular; var values; + var r; var i; triangular = factory(); values = [ - [ 0.0, 1.0, 2.0 ], - [ -2.0, -4.0, -3.0 ], - [ 2.0, 1.0, 1.5 ] + [ 2.0, 1.0, 1.5 ], + [ -5.0, -4.0, 3.14 ], + [ 0.0, 1.0, 5.5 ], ]; for ( i = 0; i < values.length; i++ ) { - t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + r = triangular( values[ i ][ 0 ], values[ i ][ 1 ], values[ i ][ 2 ] ); + t.strictEqual( isnan( r ), true, 'returns `NaN` when provided '+values[ i ] ); } t.end(); - - function badValue( arr ) { - return function() { - triangular( arr[0], arr[1], arr[2] ); - }; - } }); -// FIXME // - -/* -tape( 'the function returns a generator for creating random numbers from the specified triangular distribution', function test( t ) { +tape( 'the function returns a function for creating random numbers from a triangular distribution', opts, function test( t ) { var triangular; var rejected; var pValue; + var N; + var a; + var b; + var c; var i; var j; var x; - triangular = factory( 2.0, 4.0, 3.0, { - 'seed': 12345 - }); + a = 2.0; + b = 4.0; + c = 3.33; rejected = 0; - for ( i = 0; i < 100; i++ ) { - x = new Array( 1e3 ); + x = new Array( 1e3 ); + N = 500; + for ( i = 0; i < N; i++ ) { + triangular = factory( a, b, c ); + t.ok( true, 'seed: '+triangular.SEED ); for ( j = 0; j < x.length; j++ ) { x[ j ] = triangular(); + if ( x[ j ] < a || x[ j ] > b ) { + t.ok( false, 'returned a number outside support: '+x[ j ] ); + } } // Test using Kolmogorov-Smirnov goodness-of-fit test: - pValue = kstest( x, 'triangular', 2.0, 4.0, 3.0 ).pValue; - t.equal( typeof pValue, 'number', 'returns a p-value' ); + pValue = kstest( x, 'triangular', a, b, c ).pValue; + t.equal( typeof pValue, 'number', 'returns a p-value: '+pValue ); if ( pValue < 0.05 ) { rejected += 1; } } - t.ok( rejected / 100 < 0.05, 'null hypothesis (i.e. that numbers are drawn from Triangular(2,4,3)) is rejected in less than 5% of cases' ); + // Account for small sample sizes and few repeats... + t.ok( rejected / N < 0.10, 'null hypothesis (i.e., that numbers are drawn from Triangular('+a+','+b+','+c+')) is rejected in less than 10% of cases ('+rejected+' of '+N+')' ); t.end(); }); -*/ diff --git a/lib/node_modules/@stdlib/math/base/random/triangular/test/test.js b/lib/node_modules/@stdlib/math/base/random/triangular/test/test.js index f707cbdfbf46..284b4c641340 100644 --- a/lib/node_modules/@stdlib/math/base/random/triangular/test/test.js +++ b/lib/node_modules/@stdlib/math/base/random/triangular/test/test.js @@ -24,6 +24,11 @@ tape( 'attached to the main export is the generator name', function test( t ) { t.end(); }); +tape( 'attached to the main export is the underlying PRNG', function test( t ) { + t.equal( typeof triangular.PRNG, 'function', 'has `PRNG` property' ); + t.end(); +}); + tape( 'attached to the main export is the generator seed', function test( t ) { t.equal( typeof triangular.SEED, 'number', 'has `SEED` property' ); t.end(); @@ -31,10 +36,18 @@ tape( 'attached to the main export is the generator seed', function test( t ) { tape( 'the function returns pseudorandom numbers', function test( t ) { var r; + var a; + var b; + var c; var i; + + a = 200.0; + b = 499.974; + c = 211.33; for ( i = 0; i < 1e2; i++ ) { - r = triangular( 2.0, 4.0, 3.5 ); + r = triangular( a, b, c ); t.equal( typeof r, 'number', 'returns a number' ); + t.equal( r >= a && r <= b, true, 'within support: '+r ); } t.end(); }); diff --git a/lib/node_modules/@stdlib/math/base/random/uniform/lib/factory.js b/lib/node_modules/@stdlib/math/base/random/uniform/lib/factory.js index 20c0ea45e549..a6f55c094a13 100644 --- a/lib/node_modules/@stdlib/math/base/random/uniform/lib/factory.js +++ b/lib/node_modules/@stdlib/math/base/random/uniform/lib/factory.js @@ -4,7 +4,7 @@ var setReadOnly = require( '@stdlib/utils/define-read-only-property' ); var isObject = require( '@stdlib/utils/is-plain-object' ); -var randu = require( '@stdlib/math/base/random/randu' ); +var randu = require( '@stdlib/math/base/random/randu' ).factory; var isnan = require( '@stdlib/math/base/utils/is-nan' ); var validate = require( './validate.js' ); var uniform0 = require( './_uniform.js' ); @@ -47,13 +47,13 @@ function factory() { var b; if ( arguments.length === 0 ) { - rand = randu.factory(); + rand = randu(); } else if ( arguments.length === 1 ) { opts = arguments[ 0 ]; if ( !isObject( opts ) ) { throw new TypeError( 'invalid input argument. Options argument must be an object. Value: `'+opts+'`.' ); } - rand = randu.factory( opts ); + rand = randu( opts ); } else { a = arguments[ 0 ]; b = arguments[ 1 ]; @@ -66,9 +66,9 @@ function factory() { if ( !isObject( opts ) ) { throw new TypeError( 'invalid input argument. Options argument must be an object. Value: `'+opts+'`.' ); } - rand = randu.factory( opts ); + rand = randu( opts ); } else { - rand = randu.factory(); + rand = randu(); } } if ( a === void 0 ) { diff --git a/lib/node_modules/@stdlib/math/base/random/uniform/test/test.factory.js b/lib/node_modules/@stdlib/math/base/random/uniform/test/test.factory.js index 68625e1935fd..72db4a605264 100644 --- a/lib/node_modules/@stdlib/math/base/random/uniform/test/test.factory.js +++ b/lib/node_modules/@stdlib/math/base/random/uniform/test/test.factory.js @@ -303,13 +303,13 @@ tape( 'the function returns a function for creating random numbers from a unifor } } // Test using Kolmogorov-Smirnov goodness-of-fit test: - pValue = kstest( x, 'uniform', 2.0, 4.0 ).pValue; + pValue = kstest( x, 'uniform', a, b ).pValue; t.equal( typeof pValue, 'number', 'returns a p-value: '+pValue ); if ( pValue < 0.05 ) { rejected += 1; } } // Account for small sample sizes and few repeats... - t.ok( rejected / N < 0.08, 'null hypothesis (i.e., that numbers are drawn from Uniform(2,4)) is rejected in less than 8% of cases ('+rejected+' of '+N+')' ); + t.ok( rejected / N < 0.10, 'null hypothesis (i.e., that numbers are drawn from Uniform('+a+','+b+')) is rejected in less than 10% of cases ('+rejected+' of '+N+')' ); t.end(); }); diff --git a/lib/node_modules/@stdlib/math/base/random/weibull/README.md b/lib/node_modules/@stdlib/math/base/random/weibull/README.md index 42ac4379a43d..a5f7b217ab8e 100644 --- a/lib/node_modules/@stdlib/math/base/random/weibull/README.md +++ b/lib/node_modules/@stdlib/math/base/random/weibull/README.md @@ -11,7 +11,7 @@ var weibull = require( '@stdlib/math/base/random/weibull' ); ``` -#### weibull( alpha, beta ) +#### weibull( lambda, k ) Returns a pseudorandom number drawn from a [Weibull][weibull] distribution with parameters `lambda` (shape parameter) and `k` (scale parameter). @@ -20,32 +20,61 @@ var r = weibull( 2.0, 5.0 ); // returns ``` -If provided `lambda <= 0` or `k <= 0`, the function throws an error. +If `lambda <= 0` or `k <= 0`, the function returns `NaN`. ``` javascript var r = weibull( 2.0, -2.0 ); -// throws TypeError +// returns NaN r = weibull( -2.0, 2.0 ); -// throws TypeError +// returns NaN ``` -#### weibull.factory( \[alpha, beta, \]\[options\] ) +If `lambda` or `k` is `NaN`, the function returns `NaN`. -Returns a pseudorandom number generator (PRNG) for generating pseudorandom numbers drawn from a [Weibull][weibull] distribution. If `lambda` (shape parameter) and `k` (scale parameter) are supplied, the returned generator returns random variates from the specified distribution, otherwise the parameters have to be supplied at each generator invocation. +``` javascript +var r = weibull( NaN, 5.0 ); +// returns NaN + +r = weibull( 2.0, NaN ); +// returns NaN +``` + +#### weibull.factory( \[lambda, k, \]\[options\] ) + +Returns a pseudorandom number generator (PRNG) for generating pseudorandom numbers drawn from a [Weibull][weibull] distribution. ``` javascript -// Draw from Weibull( 1.5, 1.5 ) distribution: var rand = weibull.factory(); + var r = rand( 1.5, 1.5 ); // returns +``` + +If provided `lambda` and `k`, the returned generator returns random variates from the specified distribution. + +``` javascript +var rand = weibull.factory( 1.5, 1.5 ); + +var r = rand(); +// returns -// Draw from Weibull( 1.5, 1.5 ) distribution: -rand = weibull.factory( 1.5, 1.5 ); r = rand(); // returns ``` +If not provided `lambda` and `k`, the returned generator requires that both parameters be provided at each invocation. + +``` javascript +var rand = weibull.factory(); + +var r = rand( 1.0, 1.0 ); +// returns + +r = rand( 3.14, 2.25 ); +// returns +``` + The function accepts the following `options`: * __seed__: pseudorandom number generator seed. @@ -77,6 +106,15 @@ var name = weibull.NAME; // returns 'weibull' ``` +#### weibull.PRNG + +The underlying pseudorandom number generator. + +``` javascript +var prng = weibull.PRNG; +// returns +``` + #### weibull.SEED The value used to seed `weibull()`. @@ -102,22 +140,13 @@ for ( i = 0; i < 100; i++ ) { - - -## References - -* Ahrens, J. H., & Dieter, U. (1974). Computer methods for sampling from gamma, beta, poisson and bionomial distributions. Computing, 12(3), 223–246. doi:10.1007/BF02293108 - - - - ## Examples ``` javascript -var weibull = require( '@stdlib/math/base/random/beta' ); +var weibull = require( '@stdlib/math/base/random/weibull' ); var seed; var rand; diff --git a/lib/node_modules/@stdlib/math/base/random/weibull/lib/_weibull.js b/lib/node_modules/@stdlib/math/base/random/weibull/lib/_weibull.js new file mode 100644 index 000000000000..a494bd214beb --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/random/weibull/lib/_weibull.js @@ -0,0 +1,27 @@ +'use strict'; + +// MODULES // + +var pow = require( '@stdlib/math/base/special/pow' ); +var ln = require( '@stdlib/math/base/special/ln' ); + + +// MAIN // + +/** +* Returns a pseudorandom number drawn from a Weibull distribution. +* +* @private +* @param {Function} rand - PRNG for generating uniformly distributed numbers +* @param {PositiveNumber} lambda - shape parameter +* @param {PositiveNumber} k - scale parameter +* @returns {NonNegativeNumber} pseudorandom number +*/ +function weibull( rand, lambda, k ) { + return lambda * pow( -ln( 1.0-rand() ), 1.0/k ); +} // end FUNCTION weibull() + + +// EXPORTS // + +module.exports = weibull; diff --git a/lib/node_modules/@stdlib/math/base/random/weibull/lib/factory.js b/lib/node_modules/@stdlib/math/base/random/weibull/lib/factory.js index ebf24f4c0542..813eb55cbe0b 100644 --- a/lib/node_modules/@stdlib/math/base/random/weibull/lib/factory.js +++ b/lib/node_modules/@stdlib/math/base/random/weibull/lib/factory.js @@ -3,14 +3,14 @@ // MODULES // var setReadOnly = require( '@stdlib/utils/define-read-only-property' ); -var isPositive = require( '@stdlib/utils/is-positive-number' ).isPrimitive; var isObject = require( '@stdlib/utils/is-plain-object' ); -var randu = require( '@stdlib/math/base/random/randu' ); -var pow = require( '@stdlib/math/base/special/pow' ); -var ln = require( '@stdlib/math/base/special/ln' ); +var randu = require( '@stdlib/math/base/random/randu' ).factory; +var isnan = require( '@stdlib/math/base/utils/is-nan' ); +var validate = require( './validate.js' ); +var weibull0 = require( './_weibull.js' ); -// FACTORY // +// MAIN // /** * Returns a pseudorandom number generator for generating Weibull distributed random numbers. @@ -19,9 +19,9 @@ var ln = require( '@stdlib/math/base/special/ln' ); * @param {PositiveNumber} [k] - scale parameter * @param {Options} [options] - function options * @param {*} [options.seed] - pseudorandom number generator seed -* @throws {TypeError} lambda argument must be a positive number -* @throws {TypeError} k argument must be a positive number -* @throws {TypeError} options must be an object +* @throws {TypeError} `lambda` must be a positive number +* @throws {TypeError} `k` must be a positive number +* @throws {TypeError} options argument must be an object * @returns {Function} pseudorandom number generator * * @example @@ -38,93 +38,97 @@ var ln = require( '@stdlib/math/base/special/ln' ); */ function factory() { var lambda; - var nargs; var opts; var rand; - var ret; + var prng; + var err; var k; - nargs = arguments.length; - if ( nargs === 0 ) { - rand = randu.factory(); - } - else { - if ( isObject( arguments[ 0 ] ) ) { - opts = arguments[ 0 ]; - rand = randu.factory( opts ); + if ( arguments.length === 0 ) { + rand = randu(); + } else if ( arguments.length === 1 ) { + opts = arguments[ 0 ]; + if ( !isObject( opts ) ) { + throw new TypeError( 'invalid input argument. Options argument must be an object. Value: `' + opts + '`.' ); } - else { - lambda = arguments[ 0 ]; - k = arguments[ 1 ]; - if ( !isPositive( lambda ) ) { - throw new TypeError( 'invalid input argument. First argument `lambda` must be a positive number. Value: `' + lambda + '`.' ); - } - if ( !isPositive( k ) ) { - throw new TypeError( 'invalid input argument. Second argument `k` must be a positive number. Value: `' + k + '`.' ); - } - if ( nargs > 2 ) { - opts = arguments[ 2 ]; - if ( !isObject( opts ) ) { - throw new TypeError( 'invalid input argument. If supplied, third argument must be an options object. Value: `' + opts + '`.' ); - } - rand = randu.factory( opts ); - } else { - rand = randu.factory(); + rand = randu( opts ); + } else { + lambda = arguments[ 0 ]; + k = arguments[ 1 ]; + err = validate( lambda, k ); + if ( err ) { + throw err; + } + if ( arguments.length > 2 ) { + opts = arguments[ 2 ]; + if ( !isObject( opts ) ) { + throw new TypeError( 'invalid input argument. Options argument must be an object. Value: `' + opts + '`.' ); } + rand = randu( opts ); + } else { + rand = randu(); } } - - if ( lambda !== void 0 ) { - ret = weibull1; + if ( lambda === void 0 ) { + prng = weibull2; } else { - ret = weibull2; + prng = weibull1; } - setReadOnly( ret, 'NAME', 'weibull' ); - setReadOnly( ret, 'SEED', rand.SEED ); - setReadOnly( ret, 'PRNG', rand ); - return ret; + setReadOnly( prng, 'NAME', 'weibull' ); + setReadOnly( prng, 'SEED', rand.SEED ); + setReadOnly( prng, 'PRNG', rand ); + + return prng; /** - * Returns a random number drawn from a Weibull distribution. + * Returns a pseudorandom number drawn from a Weibull distribution. * * @private * @returns {NonNegativeNumber} pseudorandom number * * @example - * var y = weibull1(); + * var v = weibull1(); * // returns */ function weibull1() { - var u = rand(); - return lambda * pow( -ln( 1.0 - u ), 1.0/k ); + return weibull0( rand, lambda, k ); } // end FUNCTION weibull1() /** - * Returns a random number drawn from a Weibull distribution. + * Returns a pseudorandom number drawn from a Weibull distribution. * * @private * @param {PositiveNumber} lambda - shape parameter * @param {PositiveNumber} k - scale parameter - * @throws {TypeError} lambda argument must be a positive number - * @throws {TypeError} k argument must be a positive number * @returns {NonNegativeNumber} pseudorandom number * * @example - * var y = weibull2( 2.0, 1.0 ); + * var v = weibull2( 2.0, 1.0 ); * // returns + * + * @example + * var v = weibull2( 3.0, 0.0 ); + * // returns NaN + * + * @example + * var v = weibull2( 0.0, 2.0 ); + * // returns NaN + * + * @example + * var v = weibull2( NaN, NaN ); + * // returns NaN */ function weibull2( lambda, k ) { - var u; - if ( !isPositive( lambda ) ) { - throw new TypeError( 'invalid input argument. First argument `lambda` must be a positive number. Value: `' + lambda + '`.' ); - } - if ( !isPositive( k ) ) { - throw new TypeError( 'invalid input argument. Second argument `k` must be a positive number. Value: `' + k + '`.' ); + if ( + isnan( lambda ) || + isnan( k ) || + lambda <= 0.0 || + k <= 0.0 + ) { + return NaN; } - u = rand(); - return lambda * pow( -ln( 1.0 - u ), 1.0/k ); + return weibull0( rand, lambda, k ); } // end FUNCTION weibull2() - } // end FUNCTION factory() diff --git a/lib/node_modules/@stdlib/math/base/random/weibull/lib/validate.js b/lib/node_modules/@stdlib/math/base/random/weibull/lib/validate.js new file mode 100644 index 000000000000..b94143ab902a --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/random/weibull/lib/validate.js @@ -0,0 +1,37 @@ +'use strict'; + +// MODULES // + +var isPositive = require( '@stdlib/utils/is-positive-number' ).isPrimitive; + + +// MAIN // + +/** +* Validates parameters. +* +* @private +* @param {PositiveNumber} lambda - shape parameter +* @param {PositiveNumber} k - scale parameter +* @returns {(Error|null)} error or null +* +* @example +* var err = validate( 1.0, 2.0 ); +* if ( err ) { +* throw err; +* } +*/ +function validate( lambda, k ) { + if ( !isPositive( lambda ) ) { + return new TypeError( 'invalid input argument. Shape parameter must be a positive number. Value: `' + lambda + '`.' ); + } + if ( !isPositive( k ) ) { + return new TypeError( 'invalid input argument. Scale parameter must be a positive number. Value: `' + k + '`.' ); + } + return null; +} // end FUNCTION validate() + + +// EXPORTS // + +module.exports = validate; diff --git a/lib/node_modules/@stdlib/math/base/random/weibull/lib/weibull.js b/lib/node_modules/@stdlib/math/base/random/weibull/lib/weibull.js index 9677514424c0..4d840e964468 100644 --- a/lib/node_modules/@stdlib/math/base/random/weibull/lib/weibull.js +++ b/lib/node_modules/@stdlib/math/base/random/weibull/lib/weibull.js @@ -5,22 +5,24 @@ var factory = require( './factory.js' ); -// WEIBULL PRNG // +// MAIN // /** -* Returns a random number drawn from a Weibull distribution. +* Returns a pseudorandom number drawn from a Weibull distribution. * -* @function weibull +* @name weibull * @type {Function} * @param {PositiveNumber} lambda - shape parameter * @param {PositiveNumber} k - scale parameter -* @throws {TypeError} lambda argument must be a positive number -* @throws {TypeError} k argument must be a positive number * @returns {NonNegativeNumber} pseudorandom number * * @example -* var y = weibull( 2.0, 1.0 ); +* var v = weibull( 2.0, 3.0 ); * // returns +* +* @example +* var v = weibull( -2.0, 3.0 ); +* // returns NaN */ var weibull = factory(); diff --git a/lib/node_modules/@stdlib/math/base/random/weibull/package.json b/lib/node_modules/@stdlib/math/base/random/weibull/package.json index 13424d83a097..50be81f0557f 100644 --- a/lib/node_modules/@stdlib/math/base/random/weibull/package.json +++ b/lib/node_modules/@stdlib/math/base/random/weibull/package.json @@ -15,10 +15,14 @@ "statistics", "stats", "prng", + "rng", "pseudorandom", "random", "rand", "weibull", + "distribution", + "dist", + "continuous", "generator", "seed", "seedable", diff --git a/lib/node_modules/@stdlib/math/base/random/weibull/test/test.factory.js b/lib/node_modules/@stdlib/math/base/random/weibull/test/test.factory.js index 5f1244deb1c4..89e33711674b 100644 --- a/lib/node_modules/@stdlib/math/base/random/weibull/test/test.factory.js +++ b/lib/node_modules/@stdlib/math/base/random/weibull/test/test.factory.js @@ -5,9 +5,17 @@ var tape = require( 'tape' ); var kstest = require( '@stdlib/math/generics/statistics/kstest' ); var round = require( '@stdlib/math/base/special/round' ); +var isnan = require( '@stdlib/math/base/utils/is-nan' ); var factory = require( './../lib/factory.js' ); +// VARIABLES // + +var opts = { + 'skip': ( process.env.TEST_MODE === 'coverage' ) +}; + + // TESTS // tape( 'main export is a function', function test( t ) { @@ -71,6 +79,12 @@ tape( 'attached to the returned function is the generator name', function test( t.end(); }); +tape( 'attached to the returned function is the underlying PRNG', function test( t ) { + var weibull = factory(); + t.equal( typeof weibull.PRNG, 'function', 'has `PRNG` property' ); + t.end(); +}); + tape( 'attached to the returned function is the generator seed', function test( t ) { var weibull = factory({ 'seed': 12345 @@ -80,7 +94,7 @@ tape( 'attached to the returned function is the generator seed', function test( t.end(); }); -tape( 'the function throws an error if the `lambda` value is not a positive number value', function test( t ) { +tape( 'the function throws an error if provided a shape argument which is not a positive number', function test( t ) { var values; var i; @@ -93,6 +107,7 @@ tape( 'the function throws an error if the `lambda` value is not a positive numb undefined, NaN, [], + {}, function(){} ]; @@ -108,7 +123,7 @@ tape( 'the function throws an error if the `lambda` value is not a positive numb } }); -tape( 'the function throws an error if the `k` value is not a positive number value', function test( t ) { +tape( 'the function throws an error if provided a scale argument which is not a positive number', function test( t ) { var values; var i; @@ -137,7 +152,7 @@ tape( 'the function throws an error if the `k` value is not a positive number va } }); -tape( 'the function throws an error if the `options` is not a simple object (when `lambda` and `k` are not supplied)', function test( t ) { +tape( 'the function throws an error if provided an options argument which is not an object (no other arguments)', function test( t ) { var values; var i; @@ -164,7 +179,7 @@ tape( 'the function throws an error if the `options` is not a simple object (whe } }); -tape( 'the function throws an error if the `options` is not a simple object (when `lambda` and `k` are supplied)', function test( t ) { +tape( 'the function throws an error if provided an options argument which is not an object (other arguments)', function test( t ) { var values; var i; @@ -191,97 +206,100 @@ tape( 'the function throws an error if the `options` is not a simple object (whe } }); -tape( 'when called without parameters, the function returns a generator that throws an error if the `lambda` value is not a positive number', function test( t ) { +tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided a first argument which is `NaN`', function test( t ) { var weibull; - var values; - var i; + var r; weibull = factory(); - values = [ - -2.0, - 0.0, - '5', - null, - true, - undefined, - NaN, - [], - {}, - function(){} - ]; + r = weibull( NaN, 1.0 ); - for ( i = 0; i < values.length; i++ ) { - t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] ); - } + t.strictEqual( isnan( r ), true, 'returns NaN' ); t.end(); +}); - function badValue( value ) { - return function() { - weibull( value, 1.0 ); - }; - } +tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided a second argument which is `NaN`', function test( t ) { + var weibull; + var r; + + weibull = factory(); + r = weibull( 1.0, NaN ); + + t.strictEqual( isnan( r ), true, 'returns NaN' ); + t.end(); }); -tape( 'when called without parameters, the function returns a generator that throws an error if the `k` value is not a positive number', function test( t ) { +tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided `NaNs`', function test( t ) { var weibull; - var values; - var i; + var r; weibull = factory(); - values = [ - -2.0, - 0.0, - '5', - null, - true, - undefined, - NaN, - [], - {}, - function(){} - ]; + r = weibull( NaN, NaN ); - for ( i = 0; i < values.length; i++ ) { - t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] ); - } + t.strictEqual( isnan( r ), true, 'returns NaN' ); t.end(); +}); - function badValue( value ) { - return function() { - weibull( 1.0, value ); - }; - } +tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided a first argument which is nonpositive', function test( t ) { + var weibull; + var r; + + weibull = factory(); + + r = weibull( 0.0, 1.0 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + r = weibull( -1.0, 1.0 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + t.end(); }); -// FIXME // +tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided a second argument which is nonpositive', function test( t ) { + var weibull; + var r; + + weibull = factory(); + + r = weibull( 1.0, 0.0 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + r = weibull( 1.0, -1.0 ); + t.strictEqual( isnan( r ), true, 'returns NaN' ); + + t.end(); +}); -/* -tape( 'the function returns a generator for creating random numbers from the specified Weibull distribution', function test( t ) { +tape( 'the function returns a PRNG for generating random numbers from a Weibull distribution', opts, function test( t ) { var rejected; var weibull; var pValue; + var lambda; + var N; var i; var j; + var k; var x; - weibull = factory( 2.0, 4.0, { - 'seed': 12345 - }); + lambda = 3.14; + k = 1.2; + x = new Array( 1e3 ); rejected = 0; - for ( i = 0; i < 100; i++ ) { - x = new Array( 1e3 ); + N = 300; + for ( i = 0; i < N; i++ ) { + weibull = factory( lambda, k ); + t.ok( true, 'seed: '+weibull.SEED ); for ( j = 0; j < x.length; j++ ) { x[ j ] = weibull(); } // Test using Kolmogorov-Smirnov goodness-of-fit test: - pValue = kstest( x, 'weibull', 2.0, 4.0 ).pValue; - t.equal( typeof pValue, 'number', 'returns a p-value' ); + pValue = kstest( x, 'weibull', lambda, k ).pValue; + t.equal( typeof pValue, 'number', 'returns a p-value: '+pValue ); if ( pValue < 0.05 ) { rejected += 1; } } - t.ok( rejected / 100 < 0.05, 'null hypothesis (i.e. that numbers are drawn from Weibull(2,4)) is rejected in less than 5% of cases' ); + // Account for small sample size and few repeats... + t.ok( rejected / N < 0.10, 'null hypothesis (i.e., that numbers are drawn from Weibull('+lambda+','+k+')) is rejected in less than 10% of cases ('+rejected+' of '+N+')' ); t.end(); }); -*/ diff --git a/lib/node_modules/@stdlib/math/base/random/weibull/test/test.js b/lib/node_modules/@stdlib/math/base/random/weibull/test/test.js index 0d80fb160b39..82c377be440e 100644 --- a/lib/node_modules/@stdlib/math/base/random/weibull/test/test.js +++ b/lib/node_modules/@stdlib/math/base/random/weibull/test/test.js @@ -3,7 +3,6 @@ // MODULES // var tape = require( 'tape' ); -var kstest = require( '@stdlib/math/generics/statistics/kstest' ); var weibull = require( './../lib' ); @@ -25,6 +24,11 @@ tape( 'attached to the main export is the generator name', function test( t ) { t.end(); }); +tape( 'attached to the main export is the underlying PRNG', function test( t ) { + t.equal( typeof weibull.PRNG, 'function', 'has `PRNG` property' ); + t.end(); +}); + tape( 'attached to the main export is the generator seed', function test( t ) { t.equal( typeof weibull.SEED, 'number', 'has `SEED` property' ); t.end(); @@ -35,36 +39,8 @@ tape( 'the function returns pseudorandom numbers', function test( t ) { var i; for ( i = 0; i < 1e2; i++ ) { r = weibull( 2.0, 1.0 ); - t.equal( typeof r, 'number', 'returns a number' ); - } - t.end(); -}); - -// FIXME // - -/* -tape( 'the function returns pseudorandom numbers from the specified Weibull distribution', function test( t ) { - var rejected; - var pValue; - var i; - var j; - var x; - - rejected = 0; - for ( i = 0; i < 300; i++ ) { - x = new Array( 1e3 ); - for ( j = 0; j < x.length; j++ ) { - x[ j ] = weibull( 2.0, 4.0 ); - } - // Test using Kolmogorov-Smirnov goodness-of-fit test: - pValue = kstest( x, 'weibull', 2.0, 4.0 ).pValue; - t.equal( typeof pValue, 'number', 'returns a p-value' ); - if ( pValue <= 0.05 ) { - rejected += 1; - } + t.strictEqual( typeof r, 'number', 'returns a number' ); + t.strictEqual( r >= 0.0, true, 'returns a nonnegative number' ); } - // Use 0.07 instead of 0.05 as cut-off to accomodate randomly failing tests due to small sample sizes and few iterations... - t.ok( rejected / 300 < 0.07, 'null hypothesis (i.e. that numbers are drawn from Weibull(2,4)) is rejected in less than 7% of cases' ); t.end(); }); -*/ diff --git a/lib/node_modules/@stdlib/math/generics/statistics/chi2gof/lib/chi2gof.js b/lib/node_modules/@stdlib/math/generics/statistics/chi2gof/lib/chi2gof.js index 0b5cf7faa3b1..c41401ab1e96 100644 --- a/lib/node_modules/@stdlib/math/generics/statistics/chi2gof/lib/chi2gof.js +++ b/lib/node_modules/@stdlib/math/generics/statistics/chi2gof/lib/chi2gof.js @@ -25,8 +25,8 @@ var validate = require( './validate.js' ); /** * Performs a chi-square goodness-of-fit test. * -* @type {NonNegativeIntegerArray} x - observation frequencies -* @type {(NonNegativeNumericArray|ProbabilityArray)} p - probability array +* @param {NonNegativeIntegerArray} x - observation frequencies +* @param {(NonNegativeNumericArray|ProbabilityArray)} p - probability array * @param {Options} [options] - function options * @param {number} [options.alpha=0.05] - significance level * @param {NonNegativeInteger} [options.ddof=0] - degrees of freedom adjustment diff --git a/lib/node_modules/@stdlib/utils/is-node/lib/is_node.js b/lib/node_modules/@stdlib/utils/is-node/lib/is_node.js index 112f7ceae832..7e378f14c248 100644 --- a/lib/node_modules/@stdlib/utils/is-node/lib/is_node.js +++ b/lib/node_modules/@stdlib/utils/is-node/lib/is_node.js @@ -14,7 +14,7 @@ var globalScope = require( './global_scope.js' ); var RE = /node|io\.js/; -// IS NODE // +// MAIN // /** * Returns a boolean indicating if the runtime is Node.js. @@ -37,7 +37,13 @@ function isNode() { Global === Global.global && // Check that the global variable has the expected internal class: - nativeClass( Global ) === '[object global]' && + ( + // Node < v7 + nativeClass( Global ) === '[object global]' || + + // Node >= v7 (https://github.com/nodejs/node/issues/9274) + nativeClass( Global ) === '[object Object]' + ) && // Check that the `global` variable is equal to the global scope: globalScope === true && diff --git a/lib/node_modules/@stdlib/utils/is-node/test/test.is_node.js b/lib/node_modules/@stdlib/utils/is-node/test/test.is_node.js index edda77f29ba9..6704aac6d4bf 100644 --- a/lib/node_modules/@stdlib/utils/is-node/test/test.is_node.js +++ b/lib/node_modules/@stdlib/utils/is-node/test/test.is_node.js @@ -15,13 +15,14 @@ tape( 'main export is a function', function test( t ) { t.end(); }); -tape( 'the function returns `true` if runtime is Node.js', function test( t ) { +tape( 'the function returns `true` if runtime is Node.js (Node.js < v7)', function test( t ) { var isNode; function nativeClass( val ) { if ( val === process ) { return '[object process]'; } + // Node.js version <7 (https://github.com/nodejs/node/issues/9274): return '[object global]'; } @@ -43,6 +44,35 @@ tape( 'the function returns `true` if runtime is Node.js', function test( t ) { t.end(); }); +tape( 'the function returns `true` if runtime is Node.js (Node.js >= v7)', function test( t ) { + var isNode; + + function nativeClass( val ) { + if ( val === process ) { + return '[object process]'; + } + // Node.js version >=7 (https://github.com/nodejs/node/issues/9274): + return '[object Object]'; + } + + function isString(){} + isString.isPrimitive = alwaysTrue; + + function alwaysTrue() { + return true; + } + + isNode = proxyquire( './../lib/is_node.js', { + '@stdlib/utils/native-class': nativeClass, + '@stdlib/utils/is-plain-object': alwaysTrue, + '@stdlib/utils/is-string': isString, + './global_scope.js': true + }); + + t.equal( isNode(), true, 'returns true' ); + t.end(); +}); + tape( 'the function returns `false` if runtime is not Node.js (`global` variable does not equal the detected global variable)', function test( t ) { var isNode; @@ -54,6 +84,7 @@ tape( 'the function returns `false` if runtime is not Node.js (`global` variable if ( val === process ) { return '[object process]'; } + // Node.js version <7 (https://github.com/nodejs/node/issues/9274): return '[object global]'; } @@ -109,6 +140,7 @@ tape( 'the function returns `false` if runtime is not Node.js (`global` variable if ( val === process ) { return '[object process]'; } + // Node.js version <7 (https://github.com/nodejs/node/issues/9274): return '[object global]'; } @@ -136,6 +168,7 @@ tape( 'the function returns `false` if runtime is not Node.js (`process` variabl if ( val === process ) { return '[object beeeeeeep]'; } + // Node.js version <7 (https://github.com/nodejs/node/issues/9274): return '[object global]'; } @@ -163,6 +196,7 @@ tape( 'the function returns `false` if runtime is not Node.js (`process.versions if ( val === process ) { return '[object process]'; } + // Node.js version <7 (https://github.com/nodejs/node/issues/9274): return '[object global]'; } @@ -197,6 +231,7 @@ tape( 'the function returns `false` if runtime is not Node.js (`process.versions if ( val === process ) { return '[object process]'; } + // Node.js version <7 (https://github.com/nodejs/node/issues/9274): return '[object global]'; } @@ -231,6 +266,7 @@ tape( 'the function returns `false` if runtime is not Node.js (`process.release` if ( val === process ) { return '[object process]'; } + // Node.js version <7 (https://github.com/nodejs/node/issues/9274): return '[object global]'; } @@ -270,6 +306,7 @@ tape( 'the function returns `false` if runtime is not Node.js (`process.release. if ( val === process ) { return '[object process]'; } + // Node.js version <7 (https://github.com/nodejs/node/issues/9274): return '[object global]'; } diff --git a/lib/node_modules/@stdlib/utils/is-unity-probability-array/README.md b/lib/node_modules/@stdlib/utils/is-unity-probability-array/README.md index c00537da23c1..741de7b1b58d 100644 --- a/lib/node_modules/@stdlib/utils/is-unity-probability-array/README.md +++ b/lib/node_modules/@stdlib/utils/is-unity-probability-array/README.md @@ -8,7 +8,7 @@ ## Usage ``` javascript -var isUnityProbabilityArray = require( '@stdlib/utils/is-probability-array' ); +var isUnityProbabilityArray = require( '@stdlib/utils/is-unity-probability-array' ); ``` #### isUnityProbabilityArray( value ) @@ -29,12 +29,39 @@ bool = isUnityProbabilityArray( [ 3.14, 0.0 ] ); + + +## Notes + +* Summation of finite-precision floating-point numbers often has numerical error. For example, + + ``` javascript + var arr = [ 0.1, 0.2, 0.1, 0.1, 0.2, 0.2, 0.1 ]; // => 1.0 + var sum = 0.0; + var i; + for ( i = 0; i < arr.length; i++ ) { + sum += arr[ i ]; + } + // sum => 0.9999999999999999 + ``` + + To account for numerical error, the function tests if array elements sum to approximately one; specifically, + + ``` + 1.0 - sqrt(eps) <= sum(A) <= 1.0 + sqrt(eps) + ``` + + where `eps` is [double-precision floating-point][ieee754] epsilon (`~2.22e-16`) and `sqrt(eps) ~ 1.49e-8`. The above comparison ensures equality for approximately half the significand bits. + + + + ## Examples ``` javascript -var isUnityProbabilityArray = require( '@stdlib/utils/is-probability-array' ); +var isUnityProbabilityArray = require( '@stdlib/utils/is-unity-probability-array' ); var arr = [ 0.0, 1.0 ]; var bool = isUnityProbabilityArray( arr ); @@ -68,4 +95,6 @@ bool = isUnityProbabilityArray( null ); +[ieee754]: https://en.wikipedia.org/wiki/IEEE_floating_point + diff --git a/lib/node_modules/@stdlib/utils/is-unity-probability-array/lib/is_unity_probability_array.js b/lib/node_modules/@stdlib/utils/is-unity-probability-array/lib/is_unity_probability_array.js index a6aa19069ea9..45d365360353 100644 --- a/lib/node_modules/@stdlib/utils/is-unity-probability-array/lib/is_unity_probability_array.js +++ b/lib/node_modules/@stdlib/utils/is-unity-probability-array/lib/is_unity_probability_array.js @@ -4,7 +4,7 @@ var isNumericArray = require( '@stdlib/utils/is-numeric-array' ); var absdiff = require( '@stdlib/math/base/utils/absolute-difference' ); -var FLOAT64_EPS = require( '@stdlib/math/constants/float64-eps' ); +var FLOAT64_SQRT_EPS = require( '@stdlib/math/constants/float64-sqrt-eps' ); // MAIN // @@ -42,7 +42,7 @@ function isUnityProbabilityArray( v ) { } sum += v[ i ]; } - return ( absdiff( sum, 1.0 ) <= FLOAT64_EPS ); + return ( absdiff( sum, 1.0 ) <= FLOAT64_SQRT_EPS ); } return false; } // end FUNCTION isUnityProbabilityArray()