From fa5e691d640ee6ff275022e523b6052965928369 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 10:15:19 -0700 Subject: [PATCH 01/21] Increase test threshold --- .../@stdlib/math/base/random/geometric/test/test.factory.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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(); }); From 67867442cb8abc01245872d1a97a08f014bde076 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 14:31:18 -0700 Subject: [PATCH 02/21] Fix JSDoc annotations --- .../@stdlib/math/generics/statistics/chi2gof/lib/chi2gof.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 7052bad955a2943e872d9e8190b3a67f0f5bf702 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 16:12:49 -0700 Subject: [PATCH 03/21] Run tests on Node v6 --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index cb2eaca7a8a5..0e8533e9faac 100644 --- a/circle.yml +++ b/circle.yml @@ -10,7 +10,7 @@ machine: # Custom environment dependencies: dependencies: override: - - 'nvm install node && nvm use node && npm update -g npm' + - 'nvm install 6 && nvm use 6 && npm update -g npm' # Custom test commands: From 46bc9cf6ba962043a3f6e350a3669c9ebb2b7f6c Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 19:23:58 -0700 Subject: [PATCH 04/21] Increase tolerance to sqrt(eps) and add note about approximate equality to README --- .../is-unity-probability-array/README.md | 33 +++++++++++++++++-- .../lib/is_unity_probability_array.js | 4 +-- 2 files changed, 33 insertions(+), 4 deletions(-) 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() From ff7d957cdd23364b89aacb36f73109c930da4f17 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 20:02:09 -0700 Subject: [PATCH 05/21] Fix duplicate ids --- docs/references/bib.bib | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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}, From 926fbb55409f1dbb985b68ce939ebbe231bcde5c Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 20:02:38 -0700 Subject: [PATCH 06/21] Fix reference id --- .../@stdlib/math/base/random/binomial/README.md | 4 ++-- .../@stdlib/math/base/random/binomial/lib/binomial.js | 6 +++--- .../@stdlib/math/base/random/binomial/lib/sample2.js | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) 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 From f6b581f879ae835e824ee96d3767fb26b95ae09c Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 21:39:00 -0700 Subject: [PATCH 07/21] Return `NaN` if provided invalid arguments, add goodness-of-fit tests, and clean-up --- .../math/base/random/poisson/README.md | 51 ++++- .../math/base/random/poisson/lib/_poisson.js | 29 +++ .../math/base/random/poisson/lib/factory.js | 186 +++++------------- .../math/base/random/poisson/lib/knuth.js | 41 ++++ .../math/base/random/poisson/lib/poisson.js | 30 ++- .../math/base/random/poisson/lib/rejection.js | 104 ++++++++++ .../math/base/random/poisson/package.json | 3 + .../base/random/poisson/test/test.factory.js | 178 +++++++++++++++-- .../math/base/random/poisson/test/test.js | 16 +- .../random/poisson/test/test.rejection.js | 36 ++++ 10 files changed, 504 insertions(+), 170 deletions(-) create mode 100644 lib/node_modules/@stdlib/math/base/random/poisson/lib/_poisson.js create mode 100644 lib/node_modules/@stdlib/math/base/random/poisson/lib/knuth.js create mode 100644 lib/node_modules/@stdlib/math/base/random/poisson/lib/rejection.js create mode 100644 lib/node_modules/@stdlib/math/base/random/poisson/test/test.rejection.js 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..2a99d73d4eb7 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 `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.1080/00949659308811496 + 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..cde160bc1a7b 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,46 @@ 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; + if ( lambda === void 0 ) { + prng = poisson2; } else { - ret = poisson2; + 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.PRNG ); + + 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 +90,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..d82b745e1801 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.1080/00949659308811496 +* +* +* @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(); +}); From f2fee3d1312187c91edc39277369fb8d3b664224 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 21:42:10 -0700 Subject: [PATCH 08/21] Fix exposed underlying PRNG --- .../@stdlib/math/base/random/poisson/lib/factory.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 cde160bc1a7b..a988b5671acb 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 @@ -75,7 +75,7 @@ function factory() { } setReadOnly( prng, 'NAME', 'poisson' ); setReadOnly( prng, 'SEED', rand.SEED ); - setReadOnly( prng, 'PRNG', rand.PRNG ); + setReadOnly( prng, 'PRNG', rand ); return prng; From 95e391d0fcac2c7f1aec821629ed4448a5b38449 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 21:45:17 -0700 Subject: [PATCH 09/21] Fix reference DOI link --- lib/node_modules/@stdlib/math/base/random/poisson/README.md | 2 +- .../@stdlib/math/base/random/poisson/lib/poisson.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 2a99d73d4eb7..828ddb829e57 100644 --- a/lib/node_modules/@stdlib/math/base/random/poisson/README.md +++ b/lib/node_modules/@stdlib/math/base/random/poisson/README.md @@ -185,6 +185,6 @@ for ( i = 0; i < 100; i++ ) { [poisson]: https://en.wikipedia.org/wiki/Poisson_distribution -[@hormann:1993b]: http://dx.doi.org/10.1080/00949659308811496 +[@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 index d82b745e1801..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 @@ -20,7 +20,7 @@ var factory = require( './factory.js' ); * * 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.1080/00949659308811496 +* [@hormann:1993b]: http://dx.doi.org/10.1016/0167-6687(93)90997-4 * * * @name poisson From 24d5235513f4ed0f75202a9ccc69c2ebc8fa41dc Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 21:46:17 -0700 Subject: [PATCH 10/21] Fix missing verb --- lib/node_modules/@stdlib/math/base/random/exponential/README.md | 2 +- lib/node_modules/@stdlib/math/base/random/poisson/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/poisson/README.md b/lib/node_modules/@stdlib/math/base/random/poisson/README.md index 828ddb829e57..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,7 +20,7 @@ var r = poisson( 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 = poisson( -2.0 ); From 36b83cd60ff21522598e1714b1d334d4f5997972 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 22:15:01 -0700 Subject: [PATCH 11/21] Add test value --- .../@stdlib/math/base/random/exponential/test/test.factory.js | 1 + 1 file changed, 1 insertion(+) 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(){} ]; From c4c8a86a923ae8bcc8c22c8725b81063fe391a72 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 22:25:23 -0700 Subject: [PATCH 12/21] Return `NaN` if provided invalid arguments, enable KS tests, and clean-up --- .../math/base/random/rayleigh/README.md | 44 +++++++-- .../base/random/rayleigh/lib/_rayleigh.js | 26 +++++ .../math/base/random/rayleigh/lib/factory.js | 94 +++++++++--------- .../math/base/random/rayleigh/lib/rayleigh.js | 15 ++- .../math/base/random/rayleigh/package.json | 4 + .../base/random/rayleigh/test/test.factory.js | 97 +++++++++++++------ .../math/base/random/rayleigh/test/test.js | 40 ++------ 7 files changed, 200 insertions(+), 120 deletions(-) create mode 100644 lib/node_modules/@stdlib/math/base/random/rayleigh/lib/_rayleigh.js 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..a4f226eb0c8f 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,51 @@ 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; + if ( sigma === void 0 ) { + prng = rayleigh2; } else { - ret = rayleigh2; + 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 +90,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 +98,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 +105,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..0206b8c4d560 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(); }); -*/ From d666f93c4befad3076a60edcf7b8eb46120c4f00 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 23:03:24 -0700 Subject: [PATCH 13/21] Return `NaN` if provided an invalid argument, enable KS tests, and clean-up --- .../@stdlib/math/base/random/t/README.md | 48 +++++-- .../@stdlib/math/base/random/t/lib/_t.js | 26 ++++ .../@stdlib/math/base/random/t/lib/factory.js | 128 +++++++++--------- .../@stdlib/math/base/random/t/lib/index.js | 6 +- .../@stdlib/math/base/random/t/lib/t.js | 15 +- .../@stdlib/math/base/random/t/package.json | 7 +- .../math/base/random/t/test/test.factory.js | 99 ++++++++++---- .../@stdlib/math/base/random/t/test/test.js | 37 +---- 8 files changed, 225 insertions(+), 141 deletions(-) create mode 100644 lib/node_modules/@stdlib/math/base/random/t/lib/_t.js 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(); }); -*/ From cbcf4446d2e06b1015968affdbb74c25ef630302 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 23:03:59 -0700 Subject: [PATCH 14/21] Remove newlines --- .../@stdlib/math/base/random/exponential/lib/factory.js | 3 +-- .../@stdlib/math/base/random/poisson/lib/factory.js | 3 +-- .../@stdlib/math/base/random/rayleigh/lib/factory.js | 3 +-- .../@stdlib/math/base/random/rayleigh/test/test.js | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) 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/poisson/lib/factory.js b/lib/node_modules/@stdlib/math/base/random/poisson/lib/factory.js index a988b5671acb..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 @@ -69,8 +69,7 @@ function factory() { } if ( lambda === void 0 ) { prng = poisson2; - } - else { + } else { prng = poisson1; } setReadOnly( prng, 'NAME', 'poisson' ); 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 a4f226eb0c8f..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 @@ -69,8 +69,7 @@ function factory() { } if ( sigma === void 0 ) { prng = rayleigh2; - } - else { + } else { prng = rayleigh1; } setReadOnly( prng, 'NAME', 'rayleigh' ); 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 0206b8c4d560..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 @@ -40,7 +40,7 @@ tape( 'the function returns pseudorandom numbers', function test( t ) { for ( i = 0; i < 1e2; i++ ) { r = rayleigh( 3.14 ); t.strictEqual( typeof r, 'number', 'returns a number' ); - t.strictEqual(r >= 0.0, true, 'returns a positive number' ); + t.strictEqual( r >= 0.0, true, 'returns a positive number' ); } t.end(); }); From c9c41fbce2ba8f2a9e5aad91600d009f3e5f05a7 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 23:13:17 -0700 Subject: [PATCH 15/21] Alias factory method directly --- .../@stdlib/math/base/random/uniform/lib/factory.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 ) { From 67718de02caffbca9e132a7f415590bb5ed89ca2 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 23:40:52 -0700 Subject: [PATCH 16/21] Replace magic numbers --- .../@stdlib/math/base/random/uniform/test/test.factory.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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(); }); From 47567839bf46b3e9ea818681112712d5316c40c3 Mon Sep 17 00:00:00 2001 From: kgryte Date: Tue, 25 Oct 2016 23:53:35 -0700 Subject: [PATCH 17/21] Return `NaN` if provided invalid arguments, enable KS tests, and clean-up --- .../math/base/random/triangular/README.md | 58 +++++- .../base/random/triangular/lib/_triangular.js | 37 ++++ .../base/random/triangular/lib/factory.js | 167 +++++++----------- .../math/base/random/triangular/lib/index.js | 2 +- .../base/random/triangular/lib/triangular.js | 10 +- .../base/random/triangular/lib/validate.js | 45 +++++ .../math/base/random/triangular/package.json | 4 + .../random/triangular/test/test.factory.js | 159 +++++++---------- .../math/base/random/triangular/test/test.js | 15 +- 9 files changed, 283 insertions(+), 214 deletions(-) create mode 100644 lib/node_modules/@stdlib/math/base/random/triangular/lib/_triangular.js create mode 100644 lib/node_modules/@stdlib/math/base/random/triangular/lib/validate.js 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(); }); From 643d168d47282bdb83d635f3132aede07ec3be52 Mon Sep 17 00:00:00 2001 From: kgryte Date: Wed, 26 Oct 2016 00:19:24 -0700 Subject: [PATCH 18/21] Return `NaN` if provided invalid arguments, enable KS tests, and clean-up --- .../math/base/random/weibull/README.md | 67 ++++++--- .../math/base/random/weibull/lib/_weibull.js | 27 ++++ .../math/base/random/weibull/lib/factory.js | 124 +++++++-------- .../math/base/random/weibull/lib/validate.js | 37 +++++ .../math/base/random/weibull/lib/weibull.js | 14 +- .../math/base/random/weibull/package.json | 4 + .../base/random/weibull/test/test.factory.js | 142 ++++++++++-------- .../math/base/random/weibull/test/test.js | 38 +---- 8 files changed, 275 insertions(+), 178 deletions(-) create mode 100644 lib/node_modules/@stdlib/math/base/random/weibull/lib/_weibull.js create mode 100644 lib/node_modules/@stdlib/math/base/random/weibull/lib/validate.js 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(); }); -*/ From 7e2e2bf93d77339d6c9508d92840f4f3b6d9fab0 Mon Sep 17 00:00:00 2001 From: kgryte Date: Wed, 26 Oct 2016 00:19:52 -0700 Subject: [PATCH 19/21] Update description --- lib/node_modules/@stdlib/math/base/random/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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": {}, From 1105717abfd00669900c3a6ed160dfa399bcc1eb Mon Sep 17 00:00:00 2001 From: kgryte Date: Wed, 26 Oct 2016 00:44:12 -0700 Subject: [PATCH 20/21] Add support for Node.js v7+ Node.js version 7 updated V8, introducing a breaking change when accessing the internal class of the `global` object. Previous V8 versions returned `'[object global]'` when calling `Object#toString()`. More recent versions of V8 now return `'[object Object]'`. As documented in Node issue 9274, ensuring consistent return values across Node versions is not a priority. This commit adds an additional check to support Node versions 7+. --- .../@stdlib/utils/is-node/lib/is_node.js | 10 ++++- .../utils/is-node/test/test.is_node.js | 39 ++++++++++++++++++- 2 files changed, 46 insertions(+), 3 deletions(-) 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]'; } From 9de052313a55974f35ac5754bf91665cb3680f14 Mon Sep 17 00:00:00 2001 From: kgryte Date: Wed, 26 Oct 2016 00:50:05 -0700 Subject: [PATCH 21/21] Restore builds on the most recent Node release --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 0e8533e9faac..cb2eaca7a8a5 100644 --- a/circle.yml +++ b/circle.yml @@ -10,7 +10,7 @@ machine: # Custom environment dependencies: dependencies: override: - - 'nvm install 6 && nvm use 6 && npm update -g npm' + - 'nvm install node && nvm use node && npm update -g npm' # Custom test commands: