/Lib/test/test_random.py

http://unladen-swallow.googlecode.com/ · Python · 564 lines · 404 code · 78 blank · 82 comment · 55 complexity · af2b4dcf7a7d63c96832cc2ff302d6ae MD5 · raw file

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