11var vows = require ( "vows" ) ,
22 load = require ( "../load" ) ,
33 assert = require ( "../assert" ) ,
4- seedrandom = require ( ' seedrandom' ) ;
4+ seedrandom = require ( " seedrandom" ) ;
55
66var suite = vows . describe ( "d3.random" ) ;
77
8- /**
9- * Testing a random number generator is a bit more complicated than testing
10- * deterministic code, so we use different techniques.
11- *
12- * If the RNG is correct, each test in this suite will pass with probability
13- * at least P. The tests have been designed so that P ≥ 98%. Specific values
14- * of P are given above each case. We use the seedrandom module to get around
15- * this non-deterministic aspect -- so it is safe to assume that if the tests
16- * fail, then d3's RNG is broken.
17- *
18- * More on RNG testing here:
19- * @see http://www.johndcook.com/Beautiful_Testing_ch10.pdf
20- */
21-
22- // Overwrites Math.random to a seeded random function.
23- // (by default Math.random is seeded with current time)
24- Math . seedrandom ( 'a random seed.' ) ;
8+ // Testing a random number generator is a bit more complicated than testing
9+ // deterministic code, so we use different techniques.
10+ //
11+ // If the RNG is correct, each test in this suite will pass with probability
12+ // at least P. The tests have been designed so that P ≥ 98%. Specific values
13+ // of P are given above each case. We use the seedrandom module to get around
14+ // this non-deterministic aspect -- so it is safe to assume that if the tests
15+ // fail, then d3's RNG is broken.
16+ //
17+ // See also: http://www.johndcook.com/Beautiful_Testing_ch10.pdf
2518
2619suite . addBatch ( {
2720 "random" : {
2821 topic : load ( "math/random" ) . expression ( "d3.random" ) ,
29- "normal" : {
30- "topic" : function ( random ) { return random . normal ( - 43289 , 38.8 ) ; } ,
31-
32- // P = 98%
33- "has normal distribution" : KSTest ( normalCDF ( - 43289 , 38.8 ) )
34- } ,
35- "logNormal" : {
36- // Use reasonable values for mean here because random.logNormal() grows
37- // exponentially with the mean.
38- "topic" : function ( random ) { return random . logNormal ( 10 , 2.5 ) ; } ,
39-
40- // P = 98%
41- "has log-normal distribution" : KSTest ( logNormalCDF ( 10 , 2.5 ) )
42- } ,
43- "irwinHall" : {
44- "topic" : function ( random ) { return random . irwinHall ( 10 ) ; } ,
45-
46- // P = 98%
47- "has Irwin-Hall distribution" : KSTest ( irwinHallCDF ( 10 ) )
22+ "(using seedrandom)" : {
23+ topic : function ( random ) {
24+ _random = Math . random ;
25+ Math . seedrandom ( "a random seed." ) ;
26+ return random ;
27+ } ,
28+ "normal" : {
29+ "topic" : function ( random ) { return random . normal ( - 43289 , 38.8 ) ; } ,
30+ "has normal distribution" : KSTest ( normalCDF ( - 43289 , 38.8 ) )
31+ } ,
32+ "logNormal" : {
33+ "topic" : function ( random ) { return random . logNormal ( 10 , 2.5 ) ; } ,
34+ "has log-normal distribution" : KSTest ( logNormalCDF ( 10 , 2.5 ) )
35+ } ,
36+ "irwinHall" : {
37+ "topic" : function ( random ) { return random . irwinHall ( 10 ) ; } ,
38+ "has Irwin-Hall distribution" : KSTest ( irwinHallCDF ( 10 ) )
39+ } ,
40+ teardown : function ( ) {
41+ Math . random = _random ;
42+ }
4843 }
4944 }
5045} ) ;
@@ -59,9 +54,7 @@ suite.addBatch({
5954 *
6055 * @param cdf function(x) { returns CDF of the distribution evaluated at x }
6156 * @param n number of sample points. Higher n = better evaluation, slower test.
62- * @return function(rng) {
63- * // asserts that rng produces values fitting the distribution
64- * }
57+ * @return a function that asserts the rng produces values fitting the distribution
6558 */
6659function KSTest ( cdf , n ) {
6760 return function ( rng ) {
@@ -85,15 +78,15 @@ function KSTest(cdf, n) {
8578 }
8679}
8780
81+ // Logistic approximation to normal CDF around N(mean, stddev).
8882function normalCDF ( mean , stddev ) {
89- // Logistic approximation to normal CDF around N(mean, stddev).
9083 return function ( x ) {
9184 return 1 / ( 1 + Math . exp ( - 0.07056 * Math . pow ( ( x - mean ) / stddev , 3 ) - 1.5976 * ( x - mean ) / stddev ) ) ;
9285 }
9386}
9487
88+ // See http://en.wikipedia.org/wiki/Log-normal_distribution#Similar_distributions
9589function logNormalCDF ( mean , stddev ) {
96- // @see http://en.wikipedia.org/wiki/Log-normal_distribution#Similar_distributions
9790 var exponent = Math . PI / ( stddev * Math . sqrt ( 3 ) ) ;
9891 var numerator = Math . exp ( mean ) ;
9992 return function ( x ) {
@@ -111,15 +104,9 @@ function irwinHallCDF(n) {
111104 binoms . push ( binom ( n , k ) ) ;
112105 }
113106
114- // @see CDF at http://en.wikipedia.org/wiki/Irwin%E2%80%93Hall_distribution
107+ // See CDF at http://en.wikipedia.org/wiki/Irwin–Hall_distribution
115108 return function ( x ) {
116109 var t = 0 ;
117-
118- // What d3 calls Irwin-Hill distribution is actually a Bates distribution:
119- // the Irwin-Hall distribution divided by n. So we multiply the Bates
120- // distribution's x-value by n to get the Irwin-Hall CDF at x.
121- x *= n ;
122-
123110 for ( var k = 0 ; k < x ; k ++ ) {
124111 t += Math . pow ( - 1 , k % 2 ) * binoms [ k ] * Math . pow ( x - k , n ) ;
125112 }
0 commit comments