ยปCore Development>Code coverage>Lib/test/test_random.py

Python code coverage for Lib/test/test_random.py

#countcontent
1n/aimport unittest
2n/aimport unittest.mock
3n/aimport random
4n/aimport time
5n/aimport pickle
6n/aimport warnings
7n/afrom functools import partial
8n/afrom math import log, exp, pi, fsum, sin, factorial
9n/afrom test import support
10n/afrom fractions import Fraction
11n/a
12n/aclass TestBasicOps:
13n/a # Superclass with tests common to all generators.
14n/a # Subclasses must arrange for self.gen to retrieve the Random instance
15n/a # to be tested.
16n/a
17n/a def randomlist(self, n):
18n/a """Helper function to make a list of random numbers"""
19n/a return [self.gen.random() for i in range(n)]
20n/a
21n/a def test_autoseed(self):
22n/a self.gen.seed()
23n/a state1 = self.gen.getstate()
24n/a time.sleep(0.1)
25n/a self.gen.seed() # diffent seeds at different times
26n/a state2 = self.gen.getstate()
27n/a self.assertNotEqual(state1, state2)
28n/a
29n/a def test_saverestore(self):
30n/a N = 1000
31n/a self.gen.seed()
32n/a state = self.gen.getstate()
33n/a randseq = self.randomlist(N)
34n/a self.gen.setstate(state) # should regenerate the same sequence
35n/a self.assertEqual(randseq, self.randomlist(N))
36n/a
37n/a def test_seedargs(self):
38n/a # Seed value with a negative hash.
39n/a class MySeed(object):
40n/a def __hash__(self):
41n/a return -1729
42n/a for arg in [None, 0, 0, 1, 1, -1, -1, 10**20, -(10**20),
43n/a 3.14, 1+2j, 'a', tuple('abc'), MySeed()]:
44n/a self.gen.seed(arg)
45n/a for arg in [list(range(3)), dict(one=1)]:
46n/a self.assertRaises(TypeError, self.gen.seed, arg)
47n/a self.assertRaises(TypeError, self.gen.seed, 1, 2, 3, 4)
48n/a self.assertRaises(TypeError, type(self.gen), [])
49n/a
50n/a @unittest.mock.patch('random._urandom') # os.urandom
51n/a def test_seed_when_randomness_source_not_found(self, urandom_mock):
52n/a # Random.seed() uses time.time() when an operating system specific
53n/a # randomness source is not found. To test this on machines were it
54n/a # exists, run the above test, test_seedargs(), again after mocking
55n/a # os.urandom() so that it raises the exception expected when the
56n/a # randomness source is not available.
57n/a urandom_mock.side_effect = NotImplementedError
58n/a self.test_seedargs()
59n/a
60n/a def test_shuffle(self):
61n/a shuffle = self.gen.shuffle
62n/a lst = []
63n/a shuffle(lst)
64n/a self.assertEqual(lst, [])
65n/a lst = [37]
66n/a shuffle(lst)
67n/a self.assertEqual(lst, [37])
68n/a seqs = [list(range(n)) for n in range(10)]
69n/a shuffled_seqs = [list(range(n)) for n in range(10)]
70n/a for shuffled_seq in shuffled_seqs:
71n/a shuffle(shuffled_seq)
72n/a for (seq, shuffled_seq) in zip(seqs, shuffled_seqs):
73n/a self.assertEqual(len(seq), len(shuffled_seq))
74n/a self.assertEqual(set(seq), set(shuffled_seq))
75n/a # The above tests all would pass if the shuffle was a
76n/a # no-op. The following non-deterministic test covers that. It
77n/a # asserts that the shuffled sequence of 1000 distinct elements
78n/a # must be different from the original one. Although there is
79n/a # mathematically a non-zero probability that this could
80n/a # actually happen in a genuinely random shuffle, it is
81n/a # completely negligible, given that the number of possible
82n/a # permutations of 1000 objects is 1000! (factorial of 1000),
83n/a # which is considerably larger than the number of atoms in the
84n/a # universe...
85n/a lst = list(range(1000))
86n/a shuffled_lst = list(range(1000))
87n/a shuffle(shuffled_lst)
88n/a self.assertTrue(lst != shuffled_lst)
89n/a shuffle(lst)
90n/a self.assertTrue(lst != shuffled_lst)
91n/a
92n/a def test_choice(self):
93n/a choice = self.gen.choice
94n/a with self.assertRaises(IndexError):
95n/a choice([])
96n/a self.assertEqual(choice([50]), 50)
97n/a self.assertIn(choice([25, 75]), [25, 75])
98n/a
99n/a def test_sample(self):
100n/a # For the entire allowable range of 0 <= k <= N, validate that
101n/a # the sample is of the correct length and contains only unique items
102n/a N = 100
103n/a population = range(N)
104n/a for k in range(N+1):
105n/a s = self.gen.sample(population, k)
106n/a self.assertEqual(len(s), k)
107n/a uniq = set(s)
108n/a self.assertEqual(len(uniq), k)
109n/a self.assertTrue(uniq <= set(population))
110n/a self.assertEqual(self.gen.sample([], 0), []) # test edge case N==k==0
111n/a # Exception raised if size of sample exceeds that of population
112n/a self.assertRaises(ValueError, self.gen.sample, population, N+1)
113n/a self.assertRaises(ValueError, self.gen.sample, [], -1)
114n/a
115n/a def test_sample_distribution(self):
116n/a # For the entire allowable range of 0 <= k <= N, validate that
117n/a # sample generates all possible permutations
118n/a n = 5
119n/a pop = range(n)
120n/a trials = 10000 # large num prevents false negatives without slowing normal case
121n/a for k in range(n):
122n/a expected = factorial(n) // factorial(n-k)
123n/a perms = {}
124n/a for i in range(trials):
125n/a perms[tuple(self.gen.sample(pop, k))] = None
126n/a if len(perms) == expected:
127n/a break
128n/a else:
129n/a self.fail()
130n/a
131n/a def test_sample_inputs(self):
132n/a # SF bug #801342 -- population can be any iterable defining __len__()
133n/a self.gen.sample(set(range(20)), 2)
134n/a self.gen.sample(range(20), 2)
135n/a self.gen.sample(range(20), 2)
136n/a self.gen.sample(str('abcdefghijklmnopqrst'), 2)
137n/a self.gen.sample(tuple('abcdefghijklmnopqrst'), 2)
138n/a
139n/a def test_sample_on_dicts(self):
140n/a self.assertRaises(TypeError, self.gen.sample, dict.fromkeys('abcdef'), 2)
141n/a
142n/a def test_choices(self):
143n/a choices = self.gen.choices
144n/a data = ['red', 'green', 'blue', 'yellow']
145n/a str_data = 'abcd'
146n/a range_data = range(4)
147n/a set_data = set(range(4))
148n/a
149n/a # basic functionality
150n/a for sample in [
151n/a choices(data, k=5),
152n/a choices(data, range(4), k=5),
153n/a choices(k=5, population=data, weights=range(4)),
154n/a choices(k=5, population=data, cum_weights=range(4)),
155n/a ]:
156n/a self.assertEqual(len(sample), 5)
157n/a self.assertEqual(type(sample), list)
158n/a self.assertTrue(set(sample) <= set(data))
159n/a
160n/a # test argument handling
161n/a with self.assertRaises(TypeError): # missing arguments
162n/a choices(2)
163n/a
164n/a self.assertEqual(choices(data, k=0), []) # k == 0
165n/a self.assertEqual(choices(data, k=-1), []) # negative k behaves like ``[0] * -1``
166n/a with self.assertRaises(TypeError):
167n/a choices(data, k=2.5) # k is a float
168n/a
169n/a self.assertTrue(set(choices(str_data, k=5)) <= set(str_data)) # population is a string sequence
170n/a self.assertTrue(set(choices(range_data, k=5)) <= set(range_data)) # population is a range
171n/a with self.assertRaises(TypeError):
172n/a choices(set_data, k=2) # population is not a sequence
173n/a
174n/a self.assertTrue(set(choices(data, None, k=5)) <= set(data)) # weights is None
175n/a self.assertTrue(set(choices(data, weights=None, k=5)) <= set(data))
176n/a with self.assertRaises(ValueError):
177n/a choices(data, [1,2], k=5) # len(weights) != len(population)
178n/a with self.assertRaises(TypeError):
179n/a choices(data, 10, k=5) # non-iterable weights
180n/a with self.assertRaises(TypeError):
181n/a choices(data, [None]*4, k=5) # non-numeric weights
182n/a for weights in [
183n/a [15, 10, 25, 30], # integer weights
184n/a [15.1, 10.2, 25.2, 30.3], # float weights
185n/a [Fraction(1, 3), Fraction(2, 6), Fraction(3, 6), Fraction(4, 6)], # fractional weights
186n/a [True, False, True, False] # booleans (include / exclude)
187n/a ]:
188n/a self.assertTrue(set(choices(data, weights, k=5)) <= set(data))
189n/a
190n/a with self.assertRaises(ValueError):
191n/a choices(data, cum_weights=[1,2], k=5) # len(weights) != len(population)
192n/a with self.assertRaises(TypeError):
193n/a choices(data, cum_weights=10, k=5) # non-iterable cum_weights
194n/a with self.assertRaises(TypeError):
195n/a choices(data, cum_weights=[None]*4, k=5) # non-numeric cum_weights
196n/a with self.assertRaises(TypeError):
197n/a choices(data, range(4), cum_weights=range(4), k=5) # both weights and cum_weights
198n/a for weights in [
199n/a [15, 10, 25, 30], # integer cum_weights
200n/a [15.1, 10.2, 25.2, 30.3], # float cum_weights
201n/a [Fraction(1, 3), Fraction(2, 6), Fraction(3, 6), Fraction(4, 6)], # fractional cum_weights
202n/a ]:
203n/a self.assertTrue(set(choices(data, cum_weights=weights, k=5)) <= set(data))
204n/a
205n/a # Test weight focused on a single element of the population
206n/a self.assertEqual(choices('abcd', [1, 0, 0, 0]), ['a'])
207n/a self.assertEqual(choices('abcd', [0, 1, 0, 0]), ['b'])
208n/a self.assertEqual(choices('abcd', [0, 0, 1, 0]), ['c'])
209n/a self.assertEqual(choices('abcd', [0, 0, 0, 1]), ['d'])
210n/a
211n/a # Test consistency with random.choice() for empty population
212n/a with self.assertRaises(IndexError):
213n/a choices([], k=1)
214n/a with self.assertRaises(IndexError):
215n/a choices([], weights=[], k=1)
216n/a with self.assertRaises(IndexError):
217n/a choices([], cum_weights=[], k=5)
218n/a
219n/a def test_gauss(self):
220n/a # Ensure that the seed() method initializes all the hidden state. In
221n/a # particular, through 2.2.1 it failed to reset a piece of state used
222n/a # by (and only by) the .gauss() method.
223n/a
224n/a for seed in 1, 12, 123, 1234, 12345, 123456, 654321:
225n/a self.gen.seed(seed)
226n/a x1 = self.gen.random()
227n/a y1 = self.gen.gauss(0, 1)
228n/a
229n/a self.gen.seed(seed)
230n/a x2 = self.gen.random()
231n/a y2 = self.gen.gauss(0, 1)
232n/a
233n/a self.assertEqual(x1, x2)
234n/a self.assertEqual(y1, y2)
235n/a
236n/a def test_pickling(self):
237n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
238n/a state = pickle.dumps(self.gen, proto)
239n/a origseq = [self.gen.random() for i in range(10)]
240n/a newgen = pickle.loads(state)
241n/a restoredseq = [newgen.random() for i in range(10)]
242n/a self.assertEqual(origseq, restoredseq)
243n/a
244n/a def test_bug_1727780(self):
245n/a # verify that version-2-pickles can be loaded
246n/a # fine, whether they are created on 32-bit or 64-bit
247n/a # platforms, and that version-3-pickles load fine.
248n/a files = [("randv2_32.pck", 780),
249n/a ("randv2_64.pck", 866),
250n/a ("randv3.pck", 343)]
251n/a for file, value in files:
252n/a f = open(support.findfile(file),"rb")
253n/a r = pickle.load(f)
254n/a f.close()
255n/a self.assertEqual(int(r.random()*1000), value)
256n/a
257n/a def test_bug_9025(self):
258n/a # Had problem with an uneven distribution in int(n*random())
259n/a # Verify the fix by checking that distributions fall within expectations.
260n/a n = 100000
261n/a randrange = self.gen.randrange
262n/a k = sum(randrange(6755399441055744) % 3 == 2 for i in range(n))
263n/a self.assertTrue(0.30 < k/n < .37, (k/n))
264n/a
265n/atry:
266n/a random.SystemRandom().random()
267n/aexcept NotImplementedError:
268n/a SystemRandom_available = False
269n/aelse:
270n/a SystemRandom_available = True
271n/a
272n/a@unittest.skipUnless(SystemRandom_available, "random.SystemRandom not available")
273n/aclass SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
274n/a gen = random.SystemRandom()
275n/a
276n/a def test_autoseed(self):
277n/a # Doesn't need to do anything except not fail
278n/a self.gen.seed()
279n/a
280n/a def test_saverestore(self):
281n/a self.assertRaises(NotImplementedError, self.gen.getstate)
282n/a self.assertRaises(NotImplementedError, self.gen.setstate, None)
283n/a
284n/a def test_seedargs(self):
285n/a # Doesn't need to do anything except not fail
286n/a self.gen.seed(100)
287n/a
288n/a def test_gauss(self):
289n/a self.gen.gauss_next = None
290n/a self.gen.seed(100)
291n/a self.assertEqual(self.gen.gauss_next, None)
292n/a
293n/a def test_pickling(self):
294n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
295n/a self.assertRaises(NotImplementedError, pickle.dumps, self.gen, proto)
296n/a
297n/a def test_53_bits_per_float(self):
298n/a # This should pass whenever a C double has 53 bit precision.
299n/a span = 2 ** 53
300n/a cum = 0
301n/a for i in range(100):
302n/a cum |= int(self.gen.random() * span)
303n/a self.assertEqual(cum, span-1)
304n/a
305n/a def test_bigrand(self):
306n/a # The randrange routine should build-up the required number of bits
307n/a # in stages so that all bit positions are active.
308n/a span = 2 ** 500
309n/a cum = 0
310n/a for i in range(100):
311n/a r = self.gen.randrange(span)
312n/a self.assertTrue(0 <= r < span)
313n/a cum |= r
314n/a self.assertEqual(cum, span-1)
315n/a
316n/a def test_bigrand_ranges(self):
317n/a for i in [40,80, 160, 200, 211, 250, 375, 512, 550]:
318n/a start = self.gen.randrange(2 ** (i-2))
319n/a stop = self.gen.randrange(2 ** i)
320n/a if stop <= start:
321n/a continue
322n/a self.assertTrue(start <= self.gen.randrange(start, stop) < stop)
323n/a
324n/a def test_rangelimits(self):
325n/a for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]:
326n/a self.assertEqual(set(range(start,stop)),
327n/a set([self.gen.randrange(start,stop) for i in range(100)]))
328n/a
329n/a def test_randrange_nonunit_step(self):
330n/a rint = self.gen.randrange(0, 10, 2)
331n/a self.assertIn(rint, (0, 2, 4, 6, 8))
332n/a rint = self.gen.randrange(0, 2, 2)
333n/a self.assertEqual(rint, 0)
334n/a
335n/a def test_randrange_errors(self):
336n/a raises = partial(self.assertRaises, ValueError, self.gen.randrange)
337n/a # Empty range
338n/a raises(3, 3)
339n/a raises(-721)
340n/a raises(0, 100, -12)
341n/a # Non-integer start/stop
342n/a raises(3.14159)
343n/a raises(0, 2.71828)
344n/a # Zero and non-integer step
345n/a raises(0, 42, 0)
346n/a raises(0, 42, 3.14159)
347n/a
348n/a def test_genrandbits(self):
349n/a # Verify ranges
350n/a for k in range(1, 1000):
351n/a self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k)
352n/a
353n/a # Verify all bits active
354n/a getbits = self.gen.getrandbits
355n/a for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]:
356n/a cum = 0
357n/a for i in range(100):
358n/a cum |= getbits(span)
359n/a self.assertEqual(cum, 2**span-1)
360n/a
361n/a # Verify argument checking
362n/a self.assertRaises(TypeError, self.gen.getrandbits)
363n/a self.assertRaises(TypeError, self.gen.getrandbits, 1, 2)
364n/a self.assertRaises(ValueError, self.gen.getrandbits, 0)
365n/a self.assertRaises(ValueError, self.gen.getrandbits, -1)
366n/a self.assertRaises(TypeError, self.gen.getrandbits, 10.1)
367n/a
368n/a def test_randbelow_logic(self, _log=log, int=int):
369n/a # check bitcount transition points: 2**i and 2**(i+1)-1
370n/a # show that: k = int(1.001 + _log(n, 2))
371n/a # is equal to or one greater than the number of bits in n
372n/a for i in range(1, 1000):
373n/a n = 1 << i # check an exact power of two
374n/a numbits = i+1
375n/a k = int(1.00001 + _log(n, 2))
376n/a self.assertEqual(k, numbits)
377n/a self.assertEqual(n, 2**(k-1))
378n/a
379n/a n += n - 1 # check 1 below the next power of two
380n/a k = int(1.00001 + _log(n, 2))
381n/a self.assertIn(k, [numbits, numbits+1])
382n/a self.assertTrue(2**k > n > 2**(k-2))
383n/a
384n/a n -= n >> 15 # check a little farther below the next power of two
385n/a k = int(1.00001 + _log(n, 2))
386n/a self.assertEqual(k, numbits) # note the stronger assertion
387n/a self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion
388n/a
389n/a
390n/aclass MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
391n/a gen = random.Random()
392n/a
393n/a def test_guaranteed_stable(self):
394n/a # These sequences are guaranteed to stay the same across versions of python
395n/a self.gen.seed(3456147, version=1)
396n/a self.assertEqual([self.gen.random().hex() for i in range(4)],
397n/a ['0x1.ac362300d90d2p-1', '0x1.9d16f74365005p-1',
398n/a '0x1.1ebb4352e4c4dp-1', '0x1.1a7422abf9c11p-1'])
399n/a self.gen.seed("the quick brown fox", version=2)
400n/a self.assertEqual([self.gen.random().hex() for i in range(4)],
401n/a ['0x1.1239ddfb11b7cp-3', '0x1.b3cbb5c51b120p-4',
402n/a '0x1.8c4f55116b60fp-1', '0x1.63eb525174a27p-1'])
403n/a
404n/a def test_bug_27706(self):
405n/a # Verify that version 1 seeds are unaffected by hash randomization
406n/a
407n/a self.gen.seed('nofar', version=1) # hash('nofar') == 5990528763808513177
408n/a self.assertEqual([self.gen.random().hex() for i in range(4)],
409n/a ['0x1.8645314505ad7p-1', '0x1.afb1f82e40a40p-5',
410n/a '0x1.2a59d2285e971p-1', '0x1.56977142a7880p-6'])
411n/a
412n/a self.gen.seed('rachel', version=1) # hash('rachel') == -9091735575445484789
413n/a self.assertEqual([self.gen.random().hex() for i in range(4)],
414n/a ['0x1.0b294cc856fcdp-1', '0x1.2ad22d79e77b8p-3',
415n/a '0x1.3052b9c072678p-2', '0x1.578f332106574p-3'])
416n/a
417n/a self.gen.seed('', version=1) # hash('') == 0
418n/a self.assertEqual([self.gen.random().hex() for i in range(4)],
419n/a ['0x1.b0580f98a7dbep-1', '0x1.84129978f9c1ap-1',
420n/a '0x1.aeaa51052e978p-2', '0x1.092178fb945a6p-2'])
421n/a
422n/a def test_setstate_first_arg(self):
423n/a self.assertRaises(ValueError, self.gen.setstate, (1, None, None))
424n/a
425n/a def test_setstate_middle_arg(self):
426n/a # Wrong type, s/b tuple
427n/a self.assertRaises(TypeError, self.gen.setstate, (2, None, None))
428n/a # Wrong length, s/b 625
429n/a self.assertRaises(ValueError, self.gen.setstate, (2, (1,2,3), None))
430n/a # Wrong type, s/b tuple of 625 ints
431n/a self.assertRaises(TypeError, self.gen.setstate, (2, ('a',)*625, None))
432n/a # Last element s/b an int also
433n/a self.assertRaises(TypeError, self.gen.setstate, (2, (0,)*624+('a',), None))
434n/a # Last element s/b between 0 and 624
435n/a with self.assertRaises((ValueError, OverflowError)):
436n/a self.gen.setstate((2, (1,)*624+(625,), None))
437n/a with self.assertRaises((ValueError, OverflowError)):
438n/a self.gen.setstate((2, (1,)*624+(-1,), None))
439n/a
440n/a # Little trick to make "tuple(x % (2**32) for x in internalstate)"
441n/a # raise ValueError. I cannot think of a simple way to achieve this, so
442n/a # I am opting for using a generator as the middle argument of setstate
443n/a # which attempts to cast a NaN to integer.
444n/a state_values = self.gen.getstate()[1]
445n/a state_values = list(state_values)
446n/a state_values[-1] = float('nan')
447n/a state = (int(x) for x in state_values)
448n/a self.assertRaises(TypeError, self.gen.setstate, (2, state, None))
449n/a
450n/a def test_referenceImplementation(self):
451n/a # Compare the python implementation with results from the original
452n/a # code. Create 2000 53-bit precision random floats. Compare only
453n/a # the last ten entries to show that the independent implementations
454n/a # are tracking. Here is the main() function needed to create the
455n/a # list of expected random numbers:
456n/a # void main(void){
457n/a # int i;
458n/a # unsigned long init[4]={61731, 24903, 614, 42143}, length=4;
459n/a # init_by_array(init, length);
460n/a # for (i=0; i<2000; i++) {
461n/a # printf("%.15f ", genrand_res53());
462n/a # if (i%5==4) printf("\n");
463n/a # }
464n/a # }
465n/a expected = [0.45839803073713259,
466n/a 0.86057815201978782,
467n/a 0.92848331726782152,
468n/a 0.35932681119782461,
469n/a 0.081823493762449573,
470n/a 0.14332226470169329,
471n/a 0.084297823823520024,
472n/a 0.53814864671831453,
473n/a 0.089215024911993401,
474n/a 0.78486196105372907]
475n/a
476n/a self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96))
477n/a actual = self.randomlist(2000)[-10:]
478n/a for a, e in zip(actual, expected):
479n/a self.assertAlmostEqual(a,e,places=14)
480n/a
481n/a def test_strong_reference_implementation(self):
482n/a # Like test_referenceImplementation, but checks for exact bit-level
483n/a # equality. This should pass on any box where C double contains
484n/a # at least 53 bits of precision (the underlying algorithm suffers
485n/a # no rounding errors -- all results are exact).
486n/a from math import ldexp
487n/a
488n/a expected = [0x0eab3258d2231f,
489n/a 0x1b89db315277a5,
490n/a 0x1db622a5518016,
491n/a 0x0b7f9af0d575bf,
492n/a 0x029e4c4db82240,
493n/a 0x04961892f5d673,
494n/a 0x02b291598e4589,
495n/a 0x11388382c15694,
496n/a 0x02dad977c9e1fe,
497n/a 0x191d96d4d334c6]
498n/a self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96))
499n/a actual = self.randomlist(2000)[-10:]
500n/a for a, e in zip(actual, expected):
501n/a self.assertEqual(int(ldexp(a, 53)), e)
502n/a
503n/a def test_long_seed(self):
504n/a # This is most interesting to run in debug mode, just to make sure
505n/a # nothing blows up. Under the covers, a dynamically resized array
506n/a # is allocated, consuming space proportional to the number of bits
507n/a # in the seed. Unfortunately, that's a quadratic-time algorithm,
508n/a # so don't make this horribly big.
509n/a seed = (1 << (10000 * 8)) - 1 # about 10K bytes
510n/a self.gen.seed(seed)
511n/a
512n/a def test_53_bits_per_float(self):
513n/a # This should pass whenever a C double has 53 bit precision.
514n/a span = 2 ** 53
515n/a cum = 0
516n/a for i in range(100):
517n/a cum |= int(self.gen.random() * span)
518n/a self.assertEqual(cum, span-1)
519n/a
520n/a def test_bigrand(self):
521n/a # The randrange routine should build-up the required number of bits
522n/a # in stages so that all bit positions are active.
523n/a span = 2 ** 500
524n/a cum = 0
525n/a for i in range(100):
526n/a r = self.gen.randrange(span)
527n/a self.assertTrue(0 <= r < span)
528n/a cum |= r
529n/a self.assertEqual(cum, span-1)
530n/a
531n/a def test_bigrand_ranges(self):
532n/a for i in [40,80, 160, 200, 211, 250, 375, 512, 550]:
533n/a start = self.gen.randrange(2 ** (i-2))
534n/a stop = self.gen.randrange(2 ** i)
535n/a if stop <= start:
536n/a continue
537n/a self.assertTrue(start <= self.gen.randrange(start, stop) < stop)
538n/a
539n/a def test_rangelimits(self):
540n/a for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]:
541n/a self.assertEqual(set(range(start,stop)),
542n/a set([self.gen.randrange(start,stop) for i in range(100)]))
543n/a
544n/a def test_genrandbits(self):
545n/a # Verify cross-platform repeatability
546n/a self.gen.seed(1234567)
547n/a self.assertEqual(self.gen.getrandbits(100),
548n/a 97904845777343510404718956115)
549n/a # Verify ranges
550n/a for k in range(1, 1000):
551n/a self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k)
552n/a
553n/a # Verify all bits active
554n/a getbits = self.gen.getrandbits
555n/a for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]:
556n/a cum = 0
557n/a for i in range(100):
558n/a cum |= getbits(span)
559n/a self.assertEqual(cum, 2**span-1)
560n/a
561n/a # Verify argument checking
562n/a self.assertRaises(TypeError, self.gen.getrandbits)
563n/a self.assertRaises(TypeError, self.gen.getrandbits, 'a')
564n/a self.assertRaises(TypeError, self.gen.getrandbits, 1, 2)
565n/a self.assertRaises(ValueError, self.gen.getrandbits, 0)
566n/a self.assertRaises(ValueError, self.gen.getrandbits, -1)
567n/a
568n/a def test_randbelow_logic(self, _log=log, int=int):
569n/a # check bitcount transition points: 2**i and 2**(i+1)-1
570n/a # show that: k = int(1.001 + _log(n, 2))
571n/a # is equal to or one greater than the number of bits in n
572n/a for i in range(1, 1000):
573n/a n = 1 << i # check an exact power of two
574n/a numbits = i+1
575n/a k = int(1.00001 + _log(n, 2))
576n/a self.assertEqual(k, numbits)
577n/a self.assertEqual(n, 2**(k-1))
578n/a
579n/a n += n - 1 # check 1 below the next power of two
580n/a k = int(1.00001 + _log(n, 2))
581n/a self.assertIn(k, [numbits, numbits+1])
582n/a self.assertTrue(2**k > n > 2**(k-2))
583n/a
584n/a n -= n >> 15 # check a little farther below the next power of two
585n/a k = int(1.00001 + _log(n, 2))
586n/a self.assertEqual(k, numbits) # note the stronger assertion
587n/a self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion
588n/a
589n/a @unittest.mock.patch('random.Random.random')
590n/a def test_randbelow_overridden_random(self, random_mock):
591n/a # Random._randbelow() can only use random() when the built-in one
592n/a # has been overridden but no new getrandbits() method was supplied.
593n/a random_mock.side_effect = random.SystemRandom().random
594n/a maxsize = 1<<random.BPF
595n/a with warnings.catch_warnings():
596n/a warnings.simplefilter("ignore", UserWarning)
597n/a # Population range too large (n >= maxsize)
598n/a self.gen._randbelow(maxsize+1, maxsize = maxsize)
599n/a self.gen._randbelow(5640, maxsize = maxsize)
600n/a
601n/a # This might be going too far to test a single line, but because of our
602n/a # noble aim of achieving 100% test coverage we need to write a case in
603n/a # which the following line in Random._randbelow() gets executed:
604n/a #
605n/a # rem = maxsize % n
606n/a # limit = (maxsize - rem) / maxsize
607n/a # r = random()
608n/a # while r >= limit:
609n/a # r = random() # <== *This line* <==<
610n/a #
611n/a # Therefore, to guarantee that the while loop is executed at least
612n/a # once, we need to mock random() so that it returns a number greater
613n/a # than 'limit' the first time it gets called.
614n/a
615n/a n = 42
616n/a epsilon = 0.01
617n/a limit = (maxsize - (maxsize % n)) / maxsize
618n/a random_mock.side_effect = [limit + epsilon, limit - epsilon]
619n/a self.gen._randbelow(n, maxsize = maxsize)
620n/a
621n/a def test_randrange_bug_1590891(self):
622n/a start = 1000000000000
623n/a stop = -100000000000000000000
624n/a step = -200
625n/a x = self.gen.randrange(start, stop, step)
626n/a self.assertTrue(stop < x <= start)
627n/a self.assertEqual((x+stop)%step, 0)
628n/a
629n/a def test_choices_algorithms(self):
630n/a # The various ways of specifying weights should produce the same results
631n/a choices = self.gen.choices
632n/a n = 104729
633n/a
634n/a self.gen.seed(8675309)
635n/a a = self.gen.choices(range(n), k=10000)
636n/a
637n/a self.gen.seed(8675309)
638n/a b = self.gen.choices(range(n), [1]*n, k=10000)
639n/a self.assertEqual(a, b)
640n/a
641n/a self.gen.seed(8675309)
642n/a c = self.gen.choices(range(n), cum_weights=range(1, n+1), k=10000)
643n/a self.assertEqual(a, c)
644n/a
645n/a # Amerian Roulette
646n/a population = ['Red', 'Black', 'Green']
647n/a weights = [18, 18, 2]
648n/a cum_weights = [18, 36, 38]
649n/a expanded_population = ['Red'] * 18 + ['Black'] * 18 + ['Green'] * 2
650n/a
651n/a self.gen.seed(9035768)
652n/a a = self.gen.choices(expanded_population, k=10000)
653n/a
654n/a self.gen.seed(9035768)
655n/a b = self.gen.choices(population, weights, k=10000)
656n/a self.assertEqual(a, b)
657n/a
658n/a self.gen.seed(9035768)
659n/a c = self.gen.choices(population, cum_weights=cum_weights, k=10000)
660n/a self.assertEqual(a, c)
661n/a
662n/adef gamma(z, sqrt2pi=(2.0*pi)**0.5):
663n/a # Reflection to right half of complex plane
664n/a if z < 0.5:
665n/a return pi / sin(pi*z) / gamma(1.0-z)
666n/a # Lanczos approximation with g=7
667n/a az = z + (7.0 - 0.5)
668n/a return az ** (z-0.5) / exp(az) * sqrt2pi * fsum([
669n/a 0.9999999999995183,
670n/a 676.5203681218835 / z,
671n/a -1259.139216722289 / (z+1.0),
672n/a 771.3234287757674 / (z+2.0),
673n/a -176.6150291498386 / (z+3.0),
674n/a 12.50734324009056 / (z+4.0),
675n/a -0.1385710331296526 / (z+5.0),
676n/a 0.9934937113930748e-05 / (z+6.0),
677n/a 0.1659470187408462e-06 / (z+7.0),
678n/a ])
679n/a
680n/aclass TestDistributions(unittest.TestCase):
681n/a def test_zeroinputs(self):
682n/a # Verify that distributions can handle a series of zero inputs'
683n/a g = random.Random()
684n/a x = [g.random() for i in range(50)] + [0.0]*5
685n/a g.random = x[:].pop; g.uniform(1,10)
686n/a g.random = x[:].pop; g.paretovariate(1.0)
687n/a g.random = x[:].pop; g.expovariate(1.0)
688n/a g.random = x[:].pop; g.weibullvariate(1.0, 1.0)
689n/a g.random = x[:].pop; g.vonmisesvariate(1.0, 1.0)
690n/a g.random = x[:].pop; g.normalvariate(0.0, 1.0)
691n/a g.random = x[:].pop; g.gauss(0.0, 1.0)
692n/a g.random = x[:].pop; g.lognormvariate(0.0, 1.0)
693n/a g.random = x[:].pop; g.vonmisesvariate(0.0, 1.0)
694n/a g.random = x[:].pop; g.gammavariate(0.01, 1.0)
695n/a g.random = x[:].pop; g.gammavariate(1.0, 1.0)
696n/a g.random = x[:].pop; g.gammavariate(200.0, 1.0)
697n/a g.random = x[:].pop; g.betavariate(3.0, 3.0)
698n/a g.random = x[:].pop; g.triangular(0.0, 1.0, 1.0/3.0)
699n/a
700n/a def test_avg_std(self):
701n/a # Use integration to test distribution average and standard deviation.
702n/a # Only works for distributions which do not consume variates in pairs
703n/a g = random.Random()
704n/a N = 5000
705n/a x = [i/float(N) for i in range(1,N)]
706n/a for variate, args, mu, sigmasqrd in [
707n/a (g.uniform, (1.0,10.0), (10.0+1.0)/2, (10.0-1.0)**2/12),
708n/a (g.triangular, (0.0, 1.0, 1.0/3.0), 4.0/9.0, 7.0/9.0/18.0),
709n/a (g.expovariate, (1.5,), 1/1.5, 1/1.5**2),
710n/a (g.vonmisesvariate, (1.23, 0), pi, pi**2/3),
711n/a (g.paretovariate, (5.0,), 5.0/(5.0-1),
712n/a 5.0/((5.0-1)**2*(5.0-2))),
713n/a (g.weibullvariate, (1.0, 3.0), gamma(1+1/3.0),
714n/a gamma(1+2/3.0)-gamma(1+1/3.0)**2) ]:
715n/a g.random = x[:].pop
716n/a y = []
717n/a for i in range(len(x)):
718n/a try:
719n/a y.append(variate(*args))
720n/a except IndexError:
721n/a pass
722n/a s1 = s2 = 0
723n/a for e in y:
724n/a s1 += e
725n/a s2 += (e - mu) ** 2
726n/a N = len(y)
727n/a self.assertAlmostEqual(s1/N, mu, places=2,
728n/a msg='%s%r' % (variate.__name__, args))
729n/a self.assertAlmostEqual(s2/(N-1), sigmasqrd, places=2,
730n/a msg='%s%r' % (variate.__name__, args))
731n/a
732n/a def test_constant(self):
733n/a g = random.Random()
734n/a N = 100
735n/a for variate, args, expected in [
736n/a (g.uniform, (10.0, 10.0), 10.0),
737n/a (g.triangular, (10.0, 10.0), 10.0),
738n/a (g.triangular, (10.0, 10.0, 10.0), 10.0),
739n/a (g.expovariate, (float('inf'),), 0.0),
740n/a (g.vonmisesvariate, (3.0, float('inf')), 3.0),
741n/a (g.gauss, (10.0, 0.0), 10.0),
742n/a (g.lognormvariate, (0.0, 0.0), 1.0),
743n/a (g.lognormvariate, (-float('inf'), 0.0), 0.0),
744n/a (g.normalvariate, (10.0, 0.0), 10.0),
745n/a (g.paretovariate, (float('inf'),), 1.0),
746n/a (g.weibullvariate, (10.0, float('inf')), 10.0),
747n/a (g.weibullvariate, (0.0, 10.0), 0.0),
748n/a ]:
749n/a for i in range(N):
750n/a self.assertEqual(variate(*args), expected)
751n/a
752n/a def test_von_mises_range(self):
753n/a # Issue 17149: von mises variates were not consistently in the
754n/a # range [0, 2*PI].
755n/a g = random.Random()
756n/a N = 100
757n/a for mu in 0.0, 0.1, 3.1, 6.2:
758n/a for kappa in 0.0, 2.3, 500.0:
759n/a for _ in range(N):
760n/a sample = g.vonmisesvariate(mu, kappa)
761n/a self.assertTrue(
762n/a 0 <= sample <= random.TWOPI,
763n/a msg=("vonmisesvariate({}, {}) produced a result {} out"
764n/a " of range [0, 2*pi]").format(mu, kappa, sample))
765n/a
766n/a def test_von_mises_large_kappa(self):
767n/a # Issue #17141: vonmisesvariate() was hang for large kappas
768n/a random.vonmisesvariate(0, 1e15)
769n/a random.vonmisesvariate(0, 1e100)
770n/a
771n/a def test_gammavariate_errors(self):
772n/a # Both alpha and beta must be > 0.0
773n/a self.assertRaises(ValueError, random.gammavariate, -1, 3)
774n/a self.assertRaises(ValueError, random.gammavariate, 0, 2)
775n/a self.assertRaises(ValueError, random.gammavariate, 2, 0)
776n/a self.assertRaises(ValueError, random.gammavariate, 1, -3)
777n/a
778n/a @unittest.mock.patch('random.Random.random')
779n/a def test_gammavariate_full_code_coverage(self, random_mock):
780n/a # There are three different possibilities in the current implementation
781n/a # of random.gammavariate(), depending on the value of 'alpha'. What we
782n/a # are going to do here is to fix the values returned by random() to
783n/a # generate test cases that provide 100% line coverage of the method.
784n/a
785n/a # #1: alpha > 1.0: we want the first random number to be outside the
786n/a # [1e-7, .9999999] range, so that the continue statement executes
787n/a # once. The values of u1 and u2 will be 0.5 and 0.3, respectively.
788n/a random_mock.side_effect = [1e-8, 0.5, 0.3]
789n/a returned_value = random.gammavariate(1.1, 2.3)
790n/a self.assertAlmostEqual(returned_value, 2.53)
791n/a
792n/a # #2: alpha == 1: first random number less than 1e-7 to that the body
793n/a # of the while loop executes once. Then random.random() returns 0.45,
794n/a # which causes while to stop looping and the algorithm to terminate.
795n/a random_mock.side_effect = [1e-8, 0.45]
796n/a returned_value = random.gammavariate(1.0, 3.14)
797n/a self.assertAlmostEqual(returned_value, 2.507314166123803)
798n/a
799n/a # #3: 0 < alpha < 1. This is the most complex region of code to cover,
800n/a # as there are multiple if-else statements. Let's take a look at the
801n/a # source code, and determine the values that we need accordingly:
802n/a #
803n/a # while 1:
804n/a # u = random()
805n/a # b = (_e + alpha)/_e
806n/a # p = b*u
807n/a # if p <= 1.0: # <=== (A)
808n/a # x = p ** (1.0/alpha)
809n/a # else: # <=== (B)
810n/a # x = -_log((b-p)/alpha)
811n/a # u1 = random()
812n/a # if p > 1.0: # <=== (C)
813n/a # if u1 <= x ** (alpha - 1.0): # <=== (D)
814n/a # break
815n/a # elif u1 <= _exp(-x): # <=== (E)
816n/a # break
817n/a # return x * beta
818n/a #
819n/a # First, we want (A) to be True. For that we need that:
820n/a # b*random() <= 1.0
821n/a # r1 = random() <= 1.0 / b
822n/a #
823n/a # We now get to the second if-else branch, and here, since p <= 1.0,
824n/a # (C) is False and we take the elif branch, (E). For it to be True,
825n/a # so that the break is executed, we need that:
826n/a # r2 = random() <= _exp(-x)
827n/a # r2 <= _exp(-(p ** (1.0/alpha)))
828n/a # r2 <= _exp(-((b*r1) ** (1.0/alpha)))
829n/a
830n/a _e = random._e
831n/a _exp = random._exp
832n/a _log = random._log
833n/a alpha = 0.35
834n/a beta = 1.45
835n/a b = (_e + alpha)/_e
836n/a epsilon = 0.01
837n/a
838n/a r1 = 0.8859296441566 # 1.0 / b
839n/a r2 = 0.3678794411714 # _exp(-((b*r1) ** (1.0/alpha)))
840n/a
841n/a # These four "random" values result in the following trace:
842n/a # (A) True, (E) False --> [next iteration of while]
843n/a # (A) True, (E) True --> [while loop breaks]
844n/a random_mock.side_effect = [r1, r2 + epsilon, r1, r2]
845n/a returned_value = random.gammavariate(alpha, beta)
846n/a self.assertAlmostEqual(returned_value, 1.4499999999997544)
847n/a
848n/a # Let's now make (A) be False. If this is the case, when we get to the
849n/a # second if-else 'p' is greater than 1, so (C) evaluates to True. We
850n/a # now encounter a second if statement, (D), which in order to execute
851n/a # must satisfy the following condition:
852n/a # r2 <= x ** (alpha - 1.0)
853n/a # r2 <= (-_log((b-p)/alpha)) ** (alpha - 1.0)
854n/a # r2 <= (-_log((b-(b*r1))/alpha)) ** (alpha - 1.0)
855n/a r1 = 0.8959296441566 # (1.0 / b) + epsilon -- so that (A) is False
856n/a r2 = 0.9445400408898141
857n/a
858n/a # And these four values result in the following trace:
859n/a # (B) and (C) True, (D) False --> [next iteration of while]
860n/a # (B) and (C) True, (D) True [while loop breaks]
861n/a random_mock.side_effect = [r1, r2 + epsilon, r1, r2]
862n/a returned_value = random.gammavariate(alpha, beta)
863n/a self.assertAlmostEqual(returned_value, 1.5830349561760781)
864n/a
865n/a @unittest.mock.patch('random.Random.gammavariate')
866n/a def test_betavariate_return_zero(self, gammavariate_mock):
867n/a # betavariate() returns zero when the Gamma distribution
868n/a # that it uses internally returns this same value.
869n/a gammavariate_mock.return_value = 0.0
870n/a self.assertEqual(0.0, random.betavariate(2.71828, 3.14159))
871n/a
872n/aclass TestModule(unittest.TestCase):
873n/a def testMagicConstants(self):
874n/a self.assertAlmostEqual(random.NV_MAGICCONST, 1.71552776992141)
875n/a self.assertAlmostEqual(random.TWOPI, 6.28318530718)
876n/a self.assertAlmostEqual(random.LOG4, 1.38629436111989)
877n/a self.assertAlmostEqual(random.SG_MAGICCONST, 2.50407739677627)
878n/a
879n/a def test__all__(self):
880n/a # tests validity but not completeness of the __all__ list
881n/a self.assertTrue(set(random.__all__) <= set(dir(random)))
882n/a
883n/a def test_random_subclass_with_kwargs(self):
884n/a # SF bug #1486663 -- this used to erroneously raise a TypeError
885n/a class Subclass(random.Random):
886n/a def __init__(self, newarg=None):
887n/a random.Random.__init__(self)
888n/a Subclass(newarg=1)
889n/a
890n/a
891n/aif __name__ == "__main__":
892n/a unittest.main()