PageRenderTime 575ms CodeModel.GetById 141ms app.highlight 333ms RepoModel.GetById 92ms app.codeStats 1ms

/Lib/test/test_random.py

http://unladen-swallow.googlecode.com/
Python | 564 lines | 404 code | 78 blank | 82 comment | 92 complexity | af2b4dcf7a7d63c96832cc2ff302d6ae MD5 | raw file
  1#!/usr/bin/env python
  2
  3import unittest
  4import random
  5import time
  6import pickle
  7import warnings
  8from math import log, exp, sqrt, pi, fsum as msum
  9from test import test_support
 10
 11class TestBasicOps(unittest.TestCase):
 12    # Superclass with tests common to all generators.
 13    # Subclasses must arrange for self.gen to retrieve the Random instance
 14    # to be tested.
 15
 16    def randomlist(self, n):
 17        """Helper function to make a list of random numbers"""
 18        return [self.gen.random() for i in xrange(n)]
 19
 20    def test_autoseed(self):
 21        self.gen.seed()
 22        state1 = self.gen.getstate()
 23        time.sleep(0.1)
 24        self.gen.seed()      # diffent seeds at different times
 25        state2 = self.gen.getstate()
 26        self.assertNotEqual(state1, state2)
 27
 28    def test_saverestore(self):
 29        N = 1000
 30        self.gen.seed()
 31        state = self.gen.getstate()
 32        randseq = self.randomlist(N)
 33        self.gen.setstate(state)    # should regenerate the same sequence
 34        self.assertEqual(randseq, self.randomlist(N))
 35
 36    def test_seedargs(self):
 37        for arg in [None, 0, 0L, 1, 1L, -1, -1L, 10**20, -(10**20),
 38                    3.14, 1+2j, 'a', tuple('abc')]:
 39            self.gen.seed(arg)
 40        for arg in [range(3), dict(one=1)]:
 41            self.assertRaises(TypeError, self.gen.seed, arg)
 42        self.assertRaises(TypeError, self.gen.seed, 1, 2)
 43        self.assertRaises(TypeError, type(self.gen), [])
 44
 45    def test_jumpahead(self):
 46        self.gen.seed()
 47        state1 = self.gen.getstate()
 48        self.gen.jumpahead(100)
 49        state2 = self.gen.getstate()    # s/b distinct from state1
 50        self.assertNotEqual(state1, state2)
 51        self.gen.jumpahead(100)
 52        state3 = self.gen.getstate()    # s/b distinct from state2
 53        self.assertNotEqual(state2, state3)
 54
 55        self.assertRaises(TypeError, self.gen.jumpahead)  # needs an arg
 56        self.assertRaises(TypeError, self.gen.jumpahead, "ick")  # wrong type
 57        self.assertRaises(TypeError, self.gen.jumpahead, 2.3)  # wrong type
 58        self.assertRaises(TypeError, self.gen.jumpahead, 2, 3)  # too many
 59
 60    def test_sample(self):
 61        # For the entire allowable range of 0 <= k <= N, validate that
 62        # the sample is of the correct length and contains only unique items
 63        N = 100
 64        population = xrange(N)
 65        for k in xrange(N+1):
 66            s = self.gen.sample(population, k)
 67            self.assertEqual(len(s), k)
 68            uniq = set(s)
 69            self.assertEqual(len(uniq), k)
 70            self.failUnless(uniq <= set(population))
 71        self.assertEqual(self.gen.sample([], 0), [])  # test edge case N==k==0
 72
 73    def test_sample_distribution(self):
 74        # For the entire allowable range of 0 <= k <= N, validate that
 75        # sample generates all possible permutations
 76        n = 5
 77        pop = range(n)
 78        trials = 10000  # large num prevents false negatives without slowing normal case
 79        def factorial(n):
 80            return reduce(int.__mul__, xrange(1, n), 1)
 81        for k in xrange(n):
 82            expected = factorial(n) // factorial(n-k)
 83            perms = {}
 84            for i in xrange(trials):
 85                perms[tuple(self.gen.sample(pop, k))] = None
 86                if len(perms) == expected:
 87                    break
 88            else:
 89                self.fail()
 90
 91    def test_sample_inputs(self):
 92        # SF bug #801342 -- population can be any iterable defining __len__()
 93        self.gen.sample(set(range(20)), 2)
 94        self.gen.sample(range(20), 2)
 95        self.gen.sample(xrange(20), 2)
 96        self.gen.sample(str('abcdefghijklmnopqrst'), 2)
 97        self.gen.sample(tuple('abcdefghijklmnopqrst'), 2)
 98
 99    def test_sample_on_dicts(self):
100        self.gen.sample(dict.fromkeys('abcdefghijklmnopqrst'), 2)
101
102        # SF bug #1460340 -- random.sample can raise KeyError
103        a = dict.fromkeys(range(10)+range(10,100,2)+range(100,110))
104        self.gen.sample(a, 3)
105
106        # A followup to bug #1460340:  sampling from a dict could return
107        # a subset of its keys or of its values, depending on the size of
108        # the subset requested.
109        N = 30
110        d = dict((i, complex(i, i)) for i in xrange(N))
111        for k in xrange(N+1):
112            samp = self.gen.sample(d, k)
113            # Verify that we got ints back (keys); the values are complex.
114            for x in samp:
115                self.assert_(type(x) is int)
116        samp.sort()
117        self.assertEqual(samp, range(N))
118
119    def test_gauss(self):
120        # Ensure that the seed() method initializes all the hidden state.  In
121        # particular, through 2.2.1 it failed to reset a piece of state used
122        # by (and only by) the .gauss() method.
123
124        for seed in 1, 12, 123, 1234, 12345, 123456, 654321:
125            self.gen.seed(seed)
126            x1 = self.gen.random()
127            y1 = self.gen.gauss(0, 1)
128
129            self.gen.seed(seed)
130            x2 = self.gen.random()
131            y2 = self.gen.gauss(0, 1)
132
133            self.assertEqual(x1, x2)
134            self.assertEqual(y1, y2)
135
136    def test_pickling(self):
137        state = pickle.dumps(self.gen)
138        origseq = [self.gen.random() for i in xrange(10)]
139        newgen = pickle.loads(state)
140        restoredseq = [newgen.random() for i in xrange(10)]
141        self.assertEqual(origseq, restoredseq)
142
143    def test_bug_1727780(self):
144        # verify that version-2-pickles can be loaded
145        # fine, whether they are created on 32-bit or 64-bit
146        # platforms, and that version-3-pickles load fine.
147        files = [("randv2_32.pck", 780),
148                 ("randv2_64.pck", 866),
149                 ("randv3.pck", 343)]
150        for file, value in files:
151            f = open(test_support.findfile(file),"rb")
152            r = pickle.load(f)
153            f.close()
154            self.assertEqual(r.randrange(1000), value)
155
156class WichmannHill_TestBasicOps(TestBasicOps):
157    gen = random.WichmannHill()
158
159    def test_setstate_first_arg(self):
160        self.assertRaises(ValueError, self.gen.setstate, (2, None, None))
161
162    def test_strong_jumpahead(self):
163        # tests that jumpahead(n) semantics correspond to n calls to random()
164        N = 1000
165        s = self.gen.getstate()
166        self.gen.jumpahead(N)
167        r1 = self.gen.random()
168        # now do it the slow way
169        self.gen.setstate(s)
170        for i in xrange(N):
171            self.gen.random()
172        r2 = self.gen.random()
173        self.assertEqual(r1, r2)
174
175    def test_gauss_with_whseed(self):
176        # Ensure that the seed() method initializes all the hidden state.  In
177        # particular, through 2.2.1 it failed to reset a piece of state used
178        # by (and only by) the .gauss() method.
179
180        for seed in 1, 12, 123, 1234, 12345, 123456, 654321:
181            self.gen.whseed(seed)
182            x1 = self.gen.random()
183            y1 = self.gen.gauss(0, 1)
184
185            self.gen.whseed(seed)
186            x2 = self.gen.random()
187            y2 = self.gen.gauss(0, 1)
188
189            self.assertEqual(x1, x2)
190            self.assertEqual(y1, y2)
191
192    def test_bigrand(self):
193        # Verify warnings are raised when randrange is too large for random()
194        with warnings.catch_warnings():
195            warnings.filterwarnings("error", "Underlying random")
196            self.assertRaises(UserWarning, self.gen.randrange, 2**60)
197
198class SystemRandom_TestBasicOps(TestBasicOps):
199    gen = random.SystemRandom()
200
201    def test_autoseed(self):
202        # Doesn't need to do anything except not fail
203        self.gen.seed()
204
205    def test_saverestore(self):
206        self.assertRaises(NotImplementedError, self.gen.getstate)
207        self.assertRaises(NotImplementedError, self.gen.setstate, None)
208
209    def test_seedargs(self):
210        # Doesn't need to do anything except not fail
211        self.gen.seed(100)
212
213    def test_jumpahead(self):
214        # Doesn't need to do anything except not fail
215        self.gen.jumpahead(100)
216
217    def test_gauss(self):
218        self.gen.gauss_next = None
219        self.gen.seed(100)
220        self.assertEqual(self.gen.gauss_next, None)
221
222    def test_pickling(self):
223        self.assertRaises(NotImplementedError, pickle.dumps, self.gen)
224
225    def test_53_bits_per_float(self):
226        # This should pass whenever a C double has 53 bit precision.
227        span = 2 ** 53
228        cum = 0
229        for i in xrange(100):
230            cum |= int(self.gen.random() * span)
231        self.assertEqual(cum, span-1)
232
233    def test_bigrand(self):
234        # The randrange routine should build-up the required number of bits
235        # in stages so that all bit positions are active.
236        span = 2 ** 500
237        cum = 0
238        for i in xrange(100):
239            r = self.gen.randrange(span)
240            self.assert_(0 <= r < span)
241            cum |= r
242        self.assertEqual(cum, span-1)
243
244    def test_bigrand_ranges(self):
245        for i in [40,80, 160, 200, 211, 250, 375, 512, 550]:
246            start = self.gen.randrange(2 ** i)
247            stop = self.gen.randrange(2 ** (i-2))
248            if stop <= start:
249                return
250            self.assert_(start <= self.gen.randrange(start, stop) < stop)
251
252    def test_rangelimits(self):
253        for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]:
254            self.assertEqual(set(range(start,stop)),
255                set([self.gen.randrange(start,stop) for i in xrange(100)]))
256
257    def test_genrandbits(self):
258        # Verify ranges
259        for k in xrange(1, 1000):
260            self.assert_(0 <= self.gen.getrandbits(k) < 2**k)
261
262        # Verify all bits active
263        getbits = self.gen.getrandbits
264        for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]:
265            cum = 0
266            for i in xrange(100):
267                cum |= getbits(span)
268            self.assertEqual(cum, 2**span-1)
269
270        # Verify argument checking
271        self.assertRaises(TypeError, self.gen.getrandbits)
272        self.assertRaises(TypeError, self.gen.getrandbits, 1, 2)
273        self.assertRaises(ValueError, self.gen.getrandbits, 0)
274        self.assertRaises(ValueError, self.gen.getrandbits, -1)
275        self.assertRaises(TypeError, self.gen.getrandbits, 10.1)
276
277    def test_randbelow_logic(self, _log=log, int=int):
278        # check bitcount transition points:  2**i and 2**(i+1)-1
279        # show that: k = int(1.001 + _log(n, 2))
280        # is equal to or one greater than the number of bits in n
281        for i in xrange(1, 1000):
282            n = 1L << i # check an exact power of two
283            numbits = i+1
284            k = int(1.00001 + _log(n, 2))
285            self.assertEqual(k, numbits)
286            self.assert_(n == 2**(k-1))
287
288            n += n - 1      # check 1 below the next power of two
289            k = int(1.00001 + _log(n, 2))
290            self.assert_(k in [numbits, numbits+1])
291            self.assert_(2**k > n > 2**(k-2))
292
293            n -= n >> 15     # check a little farther below the next power of two
294            k = int(1.00001 + _log(n, 2))
295            self.assertEqual(k, numbits)        # note the stronger assertion
296            self.assert_(2**k > n > 2**(k-1))   # note the stronger assertion
297
298
299class MersenneTwister_TestBasicOps(TestBasicOps):
300    gen = random.Random()
301
302    def test_setstate_first_arg(self):
303        self.assertRaises(ValueError, self.gen.setstate, (1, None, None))
304
305    def test_setstate_middle_arg(self):
306        # Wrong type, s/b tuple
307        self.assertRaises(TypeError, self.gen.setstate, (2, None, None))
308        # Wrong length, s/b 625
309        self.assertRaises(ValueError, self.gen.setstate, (2, (1,2,3), None))
310        # Wrong type, s/b tuple of 625 ints
311        self.assertRaises(TypeError, self.gen.setstate, (2, ('a',)*625, None))
312        # Last element s/b an int also
313        self.assertRaises(TypeError, self.gen.setstate, (2, (0,)*624+('a',), None))
314
315    def test_referenceImplementation(self):
316        # Compare the python implementation with results from the original
317        # code.  Create 2000 53-bit precision random floats.  Compare only
318        # the last ten entries to show that the independent implementations
319        # are tracking.  Here is the main() function needed to create the
320        # list of expected random numbers:
321        #    void main(void){
322        #         int i;
323        #         unsigned long init[4]={61731, 24903, 614, 42143}, length=4;
324        #         init_by_array(init, length);
325        #         for (i=0; i<2000; i++) {
326        #           printf("%.15f ", genrand_res53());
327        #           if (i%5==4) printf("\n");
328        #         }
329        #     }
330        expected = [0.45839803073713259,
331                    0.86057815201978782,
332                    0.92848331726782152,
333                    0.35932681119782461,
334                    0.081823493762449573,
335                    0.14332226470169329,
336                    0.084297823823520024,
337                    0.53814864671831453,
338                    0.089215024911993401,
339                    0.78486196105372907]
340
341        self.gen.seed(61731L + (24903L<<32) + (614L<<64) + (42143L<<96))
342        actual = self.randomlist(2000)[-10:]
343        for a, e in zip(actual, expected):
344            self.assertAlmostEqual(a,e,places=14)
345
346    def test_strong_reference_implementation(self):
347        # Like test_referenceImplementation, but checks for exact bit-level
348        # equality.  This should pass on any box where C double contains
349        # at least 53 bits of precision (the underlying algorithm suffers
350        # no rounding errors -- all results are exact).
351        from math import ldexp
352
353        expected = [0x0eab3258d2231fL,
354                    0x1b89db315277a5L,
355                    0x1db622a5518016L,
356                    0x0b7f9af0d575bfL,
357                    0x029e4c4db82240L,
358                    0x04961892f5d673L,
359                    0x02b291598e4589L,
360                    0x11388382c15694L,
361                    0x02dad977c9e1feL,
362                    0x191d96d4d334c6L]
363        self.gen.seed(61731L + (24903L<<32) + (614L<<64) + (42143L<<96))
364        actual = self.randomlist(2000)[-10:]
365        for a, e in zip(actual, expected):
366            self.assertEqual(long(ldexp(a, 53)), e)
367
368    def test_long_seed(self):
369        # This is most interesting to run in debug mode, just to make sure
370        # nothing blows up.  Under the covers, a dynamically resized array
371        # is allocated, consuming space proportional to the number of bits
372        # in the seed.  Unfortunately, that's a quadratic-time algorithm,
373        # so don't make this horribly big.
374        seed = (1L << (10000 * 8)) - 1  # about 10K bytes
375        self.gen.seed(seed)
376
377    def test_53_bits_per_float(self):
378        # This should pass whenever a C double has 53 bit precision.
379        span = 2 ** 53
380        cum = 0
381        for i in xrange(100):
382            cum |= int(self.gen.random() * span)
383        self.assertEqual(cum, span-1)
384
385    def test_bigrand(self):
386        # The randrange routine should build-up the required number of bits
387        # in stages so that all bit positions are active.
388        span = 2 ** 500
389        cum = 0
390        for i in xrange(100):
391            r = self.gen.randrange(span)
392            self.assert_(0 <= r < span)
393            cum |= r
394        self.assertEqual(cum, span-1)
395
396    def test_bigrand_ranges(self):
397        for i in [40,80, 160, 200, 211, 250, 375, 512, 550]:
398            start = self.gen.randrange(2 ** i)
399            stop = self.gen.randrange(2 ** (i-2))
400            if stop <= start:
401                return
402            self.assert_(start <= self.gen.randrange(start, stop) < stop)
403
404    def test_rangelimits(self):
405        for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]:
406            self.assertEqual(set(range(start,stop)),
407                set([self.gen.randrange(start,stop) for i in xrange(100)]))
408
409    def test_genrandbits(self):
410        # Verify cross-platform repeatability
411        self.gen.seed(1234567)
412        self.assertEqual(self.gen.getrandbits(100),
413                         97904845777343510404718956115L)
414        # Verify ranges
415        for k in xrange(1, 1000):
416            self.assert_(0 <= self.gen.getrandbits(k) < 2**k)
417
418        # Verify all bits active
419        getbits = self.gen.getrandbits
420        for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]:
421            cum = 0
422            for i in xrange(100):
423                cum |= getbits(span)
424            self.assertEqual(cum, 2**span-1)
425
426        # Verify argument checking
427        self.assertRaises(TypeError, self.gen.getrandbits)
428        self.assertRaises(TypeError, self.gen.getrandbits, 'a')
429        self.assertRaises(TypeError, self.gen.getrandbits, 1, 2)
430        self.assertRaises(ValueError, self.gen.getrandbits, 0)
431        self.assertRaises(ValueError, self.gen.getrandbits, -1)
432
433    def test_randbelow_logic(self, _log=log, int=int):
434        # check bitcount transition points:  2**i and 2**(i+1)-1
435        # show that: k = int(1.001 + _log(n, 2))
436        # is equal to or one greater than the number of bits in n
437        for i in xrange(1, 1000):
438            n = 1L << i # check an exact power of two
439            numbits = i+1
440            k = int(1.00001 + _log(n, 2))
441            self.assertEqual(k, numbits)
442            self.assert_(n == 2**(k-1))
443
444            n += n - 1      # check 1 below the next power of two
445            k = int(1.00001 + _log(n, 2))
446            self.assert_(k in [numbits, numbits+1])
447            self.assert_(2**k > n > 2**(k-2))
448
449            n -= n >> 15     # check a little farther below the next power of two
450            k = int(1.00001 + _log(n, 2))
451            self.assertEqual(k, numbits)        # note the stronger assertion
452            self.assert_(2**k > n > 2**(k-1))   # note the stronger assertion
453
454    def test_randrange_bug_1590891(self):
455        start = 1000000000000
456        stop = -100000000000000000000
457        step = -200
458        x = self.gen.randrange(start, stop, step)
459        self.assert_(stop < x <= start)
460        self.assertEqual((x+stop)%step, 0)
461
462_gammacoeff = (0.9999999999995183, 676.5203681218835, -1259.139216722289,
463              771.3234287757674,  -176.6150291498386, 12.50734324009056,
464              -0.1385710331296526, 0.9934937113930748e-05, 0.1659470187408462e-06)
465
466def gamma(z, cof=_gammacoeff, g=7):
467    z -= 1.0
468    s = msum([cof[0]] + [cof[i] / (z+i) for i in range(1,len(cof))])
469    z += 0.5
470    return (z+g)**z / exp(z+g) * sqrt(2.0*pi) * s
471
472class TestDistributions(unittest.TestCase):
473    def test_zeroinputs(self):
474        # Verify that distributions can handle a series of zero inputs'
475        g = random.Random()
476        x = [g.random() for i in xrange(50)] + [0.0]*5
477        g.random = x[:].pop; g.uniform(1,10)
478        g.random = x[:].pop; g.paretovariate(1.0)
479        g.random = x[:].pop; g.expovariate(1.0)
480        g.random = x[:].pop; g.weibullvariate(1.0, 1.0)
481        g.random = x[:].pop; g.normalvariate(0.0, 1.0)
482        g.random = x[:].pop; g.gauss(0.0, 1.0)
483        g.random = x[:].pop; g.lognormvariate(0.0, 1.0)
484        g.random = x[:].pop; g.vonmisesvariate(0.0, 1.0)
485        g.random = x[:].pop; g.gammavariate(0.01, 1.0)
486        g.random = x[:].pop; g.gammavariate(1.0, 1.0)
487        g.random = x[:].pop; g.gammavariate(200.0, 1.0)
488        g.random = x[:].pop; g.betavariate(3.0, 3.0)
489        g.random = x[:].pop; g.triangular(0.0, 1.0, 1.0/3.0)
490
491    def test_avg_std(self):
492        # Use integration to test distribution average and standard deviation.
493        # Only works for distributions which do not consume variates in pairs
494        g = random.Random()
495        N = 5000
496        x = [i/float(N) for i in xrange(1,N)]
497        for variate, args, mu, sigmasqrd in [
498                (g.uniform, (1.0,10.0), (10.0+1.0)/2, (10.0-1.0)**2/12),
499                (g.triangular, (0.0, 1.0, 1.0/3.0), 4.0/9.0, 7.0/9.0/18.0),
500                (g.expovariate, (1.5,), 1/1.5, 1/1.5**2),
501                (g.paretovariate, (5.0,), 5.0/(5.0-1),
502