test_recipes.py 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387
  1. from decimal import Decimal
  2. from doctest import DocTestSuite
  3. from fractions import Fraction
  4. from functools import reduce
  5. from itertools import combinations, count, groupby, permutations
  6. from operator import mul
  7. from math import comb, factorial
  8. from sys import version_info
  9. from unittest import TestCase, skipIf
  10. from unittest.mock import patch
  11. import more_itertools as mi
  12. def load_tests(loader, tests, ignore):
  13. # Add the doctests
  14. tests.addTests(DocTestSuite('more_itertools.recipes'))
  15. return tests
  16. class TakeTests(TestCase):
  17. """Tests for ``take()``"""
  18. def test_simple_take(self):
  19. """Test basic usage"""
  20. t = mi.take(5, range(10))
  21. self.assertEqual(t, [0, 1, 2, 3, 4])
  22. def test_null_take(self):
  23. """Check the null case"""
  24. t = mi.take(0, range(10))
  25. self.assertEqual(t, [])
  26. def test_negative_take(self):
  27. """Make sure taking negative items results in a ValueError"""
  28. self.assertRaises(ValueError, lambda: mi.take(-3, range(10)))
  29. def test_take_too_much(self):
  30. """Taking more than an iterator has remaining should return what the
  31. iterator has remaining.
  32. """
  33. t = mi.take(10, range(5))
  34. self.assertEqual(t, [0, 1, 2, 3, 4])
  35. class TabulateTests(TestCase):
  36. """Tests for ``tabulate()``"""
  37. def test_simple_tabulate(self):
  38. """Test the happy path"""
  39. t = mi.tabulate(lambda x: x)
  40. f = tuple([next(t) for _ in range(3)])
  41. self.assertEqual(f, (0, 1, 2))
  42. def test_count(self):
  43. """Ensure tabulate accepts specific count"""
  44. t = mi.tabulate(lambda x: 2 * x, -1)
  45. f = (next(t), next(t), next(t))
  46. self.assertEqual(f, (-2, 0, 2))
  47. class TailTests(TestCase):
  48. """Tests for ``tail()``"""
  49. def test_iterator_greater(self):
  50. """Length of iterator is greater than requested tail"""
  51. self.assertEqual(list(mi.tail(3, iter('ABCDEFG'))), list('EFG'))
  52. def test_iterator_equal(self):
  53. """Length of iterator is equal to the requested tail"""
  54. self.assertEqual(list(mi.tail(7, iter('ABCDEFG'))), list('ABCDEFG'))
  55. def test_iterator_less(self):
  56. """Length of iterator is less than requested tail"""
  57. self.assertEqual(list(mi.tail(8, iter('ABCDEFG'))), list('ABCDEFG'))
  58. def test_sized_greater(self):
  59. """Length of sized iterable is greater than requested tail"""
  60. self.assertEqual(list(mi.tail(3, 'ABCDEFG')), list('EFG'))
  61. def test_sized_equal(self):
  62. """Length of sized iterable is less than requested tail"""
  63. self.assertEqual(list(mi.tail(7, 'ABCDEFG')), list('ABCDEFG'))
  64. def test_sized_less(self):
  65. """Length of sized iterable is less than requested tail"""
  66. self.assertEqual(list(mi.tail(8, 'ABCDEFG')), list('ABCDEFG'))
  67. class ConsumeTests(TestCase):
  68. """Tests for ``consume()``"""
  69. def test_sanity(self):
  70. """Test basic functionality"""
  71. r = (x for x in range(10))
  72. mi.consume(r, 3)
  73. self.assertEqual(3, next(r))
  74. def test_null_consume(self):
  75. """Check the null case"""
  76. r = (x for x in range(10))
  77. mi.consume(r, 0)
  78. self.assertEqual(0, next(r))
  79. def test_negative_consume(self):
  80. """Check that negative consumption throws an error"""
  81. r = (x for x in range(10))
  82. self.assertRaises(ValueError, lambda: mi.consume(r, -1))
  83. def test_total_consume(self):
  84. """Check that iterator is totally consumed by default"""
  85. r = (x for x in range(10))
  86. mi.consume(r)
  87. self.assertRaises(StopIteration, lambda: next(r))
  88. class NthTests(TestCase):
  89. """Tests for ``nth()``"""
  90. def test_basic(self):
  91. """Make sure the nth item is returned"""
  92. l = range(10)
  93. for i, v in enumerate(l):
  94. self.assertEqual(mi.nth(l, i), v)
  95. def test_default(self):
  96. """Ensure a default value is returned when nth item not found"""
  97. l = range(3)
  98. self.assertEqual(mi.nth(l, 100, "zebra"), "zebra")
  99. def test_negative_item_raises(self):
  100. """Ensure asking for a negative item raises an exception"""
  101. self.assertRaises(ValueError, lambda: mi.nth(range(10), -3))
  102. class AllEqualTests(TestCase):
  103. def test_true(self):
  104. self.assertTrue(mi.all_equal('aaaaaa'))
  105. self.assertTrue(mi.all_equal([0, 0, 0, 0]))
  106. def test_false(self):
  107. self.assertFalse(mi.all_equal('aaaaab'))
  108. self.assertFalse(mi.all_equal([0, 0, 0, 1]))
  109. def test_tricky(self):
  110. items = [1, complex(1, 0), 1.0]
  111. self.assertTrue(mi.all_equal(items))
  112. def test_empty(self):
  113. self.assertTrue(mi.all_equal(''))
  114. self.assertTrue(mi.all_equal([]))
  115. def test_one(self):
  116. self.assertTrue(mi.all_equal('0'))
  117. self.assertTrue(mi.all_equal([0]))
  118. def test_key(self):
  119. self.assertTrue(mi.all_equal('4٤໔4৪', key=int))
  120. self.assertFalse(mi.all_equal('Abc', key=str.casefold))
  121. @patch('more_itertools.recipes.groupby', autospec=True)
  122. def test_groupby_calls(self, mock_groupby):
  123. next_count = 0
  124. class _groupby(groupby):
  125. def __next__(true_self):
  126. nonlocal next_count
  127. next_count += 1
  128. return super().__next__()
  129. mock_groupby.side_effect = _groupby
  130. iterable = iter('aaaaa')
  131. self.assertTrue(mi.all_equal(iterable))
  132. self.assertEqual(list(iterable), [])
  133. self.assertEqual(next_count, 2)
  134. class QuantifyTests(TestCase):
  135. """Tests for ``quantify()``"""
  136. def test_happy_path(self):
  137. """Make sure True count is returned"""
  138. q = [True, False, True]
  139. self.assertEqual(mi.quantify(q), 2)
  140. def test_custom_predicate(self):
  141. """Ensure non-default predicates return as expected"""
  142. q = range(10)
  143. self.assertEqual(mi.quantify(q, lambda x: x % 2 == 0), 5)
  144. class PadnoneTests(TestCase):
  145. def test_basic(self):
  146. iterable = range(2)
  147. for func in (mi.pad_none, mi.padnone):
  148. with self.subTest(func=func):
  149. p = func(iterable)
  150. self.assertEqual(
  151. [0, 1, None, None], [next(p) for _ in range(4)]
  152. )
  153. class NcyclesTests(TestCase):
  154. """Tests for ``nyclces()``"""
  155. def test_happy_path(self):
  156. """cycle a sequence three times"""
  157. r = ["a", "b", "c"]
  158. n = mi.ncycles(r, 3)
  159. self.assertEqual(
  160. ["a", "b", "c", "a", "b", "c", "a", "b", "c"], list(n)
  161. )
  162. def test_null_case(self):
  163. """asking for 0 cycles should return an empty iterator"""
  164. n = mi.ncycles(range(100), 0)
  165. self.assertRaises(StopIteration, lambda: next(n))
  166. def test_pathological_case(self):
  167. """asking for negative cycles should return an empty iterator"""
  168. n = mi.ncycles(range(100), -10)
  169. self.assertRaises(StopIteration, lambda: next(n))
  170. class DotproductTests(TestCase):
  171. """Tests for ``dotproduct()``'"""
  172. def test_happy_path(self):
  173. """simple dotproduct example"""
  174. self.assertEqual(400, mi.dotproduct([10, 10], [20, 20]))
  175. class FlattenTests(TestCase):
  176. """Tests for ``flatten()``"""
  177. def test_basic_usage(self):
  178. """ensure list of lists is flattened one level"""
  179. f = [[0, 1, 2], [3, 4, 5]]
  180. self.assertEqual(list(range(6)), list(mi.flatten(f)))
  181. def test_single_level(self):
  182. """ensure list of lists is flattened only one level"""
  183. f = [[0, [1, 2]], [[3, 4], 5]]
  184. self.assertEqual([0, [1, 2], [3, 4], 5], list(mi.flatten(f)))
  185. class RepeatfuncTests(TestCase):
  186. """Tests for ``repeatfunc()``"""
  187. def test_simple_repeat(self):
  188. """test simple repeated functions"""
  189. r = mi.repeatfunc(lambda: 5)
  190. self.assertEqual([5, 5, 5, 5, 5], [next(r) for _ in range(5)])
  191. def test_finite_repeat(self):
  192. """ensure limited repeat when times is provided"""
  193. r = mi.repeatfunc(lambda: 5, times=5)
  194. self.assertEqual([5, 5, 5, 5, 5], list(r))
  195. def test_added_arguments(self):
  196. """ensure arguments are applied to the function"""
  197. r = mi.repeatfunc(lambda x: x, 2, 3)
  198. self.assertEqual([3, 3], list(r))
  199. def test_null_times(self):
  200. """repeat 0 should return an empty iterator"""
  201. r = mi.repeatfunc(range, 0, 3)
  202. self.assertRaises(StopIteration, lambda: next(r))
  203. class PairwiseTests(TestCase):
  204. """Tests for ``pairwise()``"""
  205. def test_base_case(self):
  206. """ensure an iterable will return pairwise"""
  207. p = mi.pairwise([1, 2, 3])
  208. self.assertEqual([(1, 2), (2, 3)], list(p))
  209. def test_short_case(self):
  210. """ensure an empty iterator if there's not enough values to pair"""
  211. p = mi.pairwise("a")
  212. self.assertRaises(StopIteration, lambda: next(p))
  213. def test_coverage(self):
  214. from more_itertools import recipes
  215. p = recipes._pairwise([1, 2, 3])
  216. self.assertEqual([(1, 2), (2, 3)], list(p))
  217. class GrouperTests(TestCase):
  218. def test_basic(self):
  219. seq = 'ABCDEF'
  220. for n, expected in [
  221. (3, [('A', 'B', 'C'), ('D', 'E', 'F')]),
  222. (4, [('A', 'B', 'C', 'D'), ('E', 'F', None, None)]),
  223. (5, [('A', 'B', 'C', 'D', 'E'), ('F', None, None, None, None)]),
  224. (6, [('A', 'B', 'C', 'D', 'E', 'F')]),
  225. (7, [('A', 'B', 'C', 'D', 'E', 'F', None)]),
  226. ]:
  227. with self.subTest(n=n):
  228. actual = list(mi.grouper(iter(seq), n))
  229. self.assertEqual(actual, expected)
  230. def test_fill(self):
  231. seq = 'ABCDEF'
  232. fillvalue = 'x'
  233. for n, expected in [
  234. (1, ['A', 'B', 'C', 'D', 'E', 'F']),
  235. (2, ['AB', 'CD', 'EF']),
  236. (3, ['ABC', 'DEF']),
  237. (4, ['ABCD', 'EFxx']),
  238. (5, ['ABCDE', 'Fxxxx']),
  239. (6, ['ABCDEF']),
  240. (7, ['ABCDEFx']),
  241. ]:
  242. with self.subTest(n=n):
  243. it = mi.grouper(
  244. iter(seq), n, incomplete='fill', fillvalue=fillvalue
  245. )
  246. actual = [''.join(x) for x in it]
  247. self.assertEqual(actual, expected)
  248. def test_ignore(self):
  249. seq = 'ABCDEF'
  250. for n, expected in [
  251. (1, ['A', 'B', 'C', 'D', 'E', 'F']),
  252. (2, ['AB', 'CD', 'EF']),
  253. (3, ['ABC', 'DEF']),
  254. (4, ['ABCD']),
  255. (5, ['ABCDE']),
  256. (6, ['ABCDEF']),
  257. (7, []),
  258. ]:
  259. with self.subTest(n=n):
  260. it = mi.grouper(iter(seq), n, incomplete='ignore')
  261. actual = [''.join(x) for x in it]
  262. self.assertEqual(actual, expected)
  263. def test_strict(self):
  264. seq = 'ABCDEF'
  265. for n, expected in [
  266. (1, ['A', 'B', 'C', 'D', 'E', 'F']),
  267. (2, ['AB', 'CD', 'EF']),
  268. (3, ['ABC', 'DEF']),
  269. (6, ['ABCDEF']),
  270. ]:
  271. with self.subTest(n=n):
  272. it = mi.grouper(iter(seq), n, incomplete='strict')
  273. actual = [''.join(x) for x in it]
  274. self.assertEqual(actual, expected)
  275. def test_strict_fails(self):
  276. seq = 'ABCDEF'
  277. for n in [4, 5, 7]:
  278. with self.subTest(n=n):
  279. with self.assertRaises(ValueError):
  280. list(mi.grouper(iter(seq), n, incomplete='strict'))
  281. def test_invalid_incomplete(self):
  282. with self.assertRaises(ValueError):
  283. list(mi.grouper('ABCD', 3, incomplete='bogus'))
  284. class RoundrobinTests(TestCase):
  285. """Tests for ``roundrobin()``"""
  286. def test_even_groups(self):
  287. """Ensure ordered output from evenly populated iterables"""
  288. self.assertEqual(
  289. list(mi.roundrobin('ABC', [1, 2, 3], range(3))),
  290. ['A', 1, 0, 'B', 2, 1, 'C', 3, 2],
  291. )
  292. def test_uneven_groups(self):
  293. """Ensure ordered output from unevenly populated iterables"""
  294. self.assertEqual(
  295. list(mi.roundrobin('ABCD', [1, 2], range(0))),
  296. ['A', 1, 'B', 2, 'C', 'D'],
  297. )
  298. class PartitionTests(TestCase):
  299. """Tests for ``partition()``"""
  300. def test_bool(self):
  301. lesser, greater = mi.partition(lambda x: x > 5, range(10))
  302. self.assertEqual(list(lesser), [0, 1, 2, 3, 4, 5])
  303. self.assertEqual(list(greater), [6, 7, 8, 9])
  304. def test_arbitrary(self):
  305. divisibles, remainders = mi.partition(lambda x: x % 3, range(10))
  306. self.assertEqual(list(divisibles), [0, 3, 6, 9])
  307. self.assertEqual(list(remainders), [1, 2, 4, 5, 7, 8])
  308. def test_pred_is_none(self):
  309. falses, trues = mi.partition(None, range(3))
  310. self.assertEqual(list(falses), [0])
  311. self.assertEqual(list(trues), [1, 2])
  312. class PowersetTests(TestCase):
  313. """Tests for ``powerset()``"""
  314. def test_combinatorics(self):
  315. """Ensure a proper enumeration"""
  316. p = mi.powerset([1, 2, 3])
  317. self.assertEqual(
  318. list(p), [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
  319. )
  320. class UniqueEverseenTests(TestCase):
  321. def test_everseen(self):
  322. u = mi.unique_everseen('AAAABBBBCCDAABBB')
  323. self.assertEqual(['A', 'B', 'C', 'D'], list(u))
  324. def test_custom_key(self):
  325. u = mi.unique_everseen('aAbACCc', key=str.lower)
  326. self.assertEqual(list('abC'), list(u))
  327. def test_unhashable(self):
  328. iterable = ['a', [1, 2, 3], [1, 2, 3], 'a']
  329. u = mi.unique_everseen(iterable)
  330. self.assertEqual(list(u), ['a', [1, 2, 3]])
  331. def test_unhashable_key(self):
  332. iterable = ['a', [1, 2, 3], [1, 2, 3], 'a']
  333. u = mi.unique_everseen(iterable, key=lambda x: x)
  334. self.assertEqual(list(u), ['a', [1, 2, 3]])
  335. class UniqueJustseenTests(TestCase):
  336. def test_justseen(self):
  337. u = mi.unique_justseen('AAAABBBCCDABB')
  338. self.assertEqual(list('ABCDAB'), list(u))
  339. def test_custom_key(self):
  340. u = mi.unique_justseen('AABCcAD', str.lower)
  341. self.assertEqual(list('ABCAD'), list(u))
  342. class UniqueTests(TestCase):
  343. def test_basic(self):
  344. iterable = [0, 1, 1, 8, 9, 9, 9, 8, 8, 1, 9, 9]
  345. actual = list(mi.unique(iterable))
  346. expected = [0, 1, 8, 9]
  347. self.assertEqual(actual, expected)
  348. def test_key(self):
  349. iterable = ['1', '1', '10', '10', '2', '2', '20', '20']
  350. actual = list(mi.unique(iterable, key=int))
  351. expected = ['1', '2', '10', '20']
  352. self.assertEqual(actual, expected)
  353. def test_reverse(self):
  354. iterable = ['1', '1', '10', '10', '2', '2', '20', '20']
  355. actual = list(mi.unique(iterable, key=int, reverse=True))
  356. expected = ['20', '10', '2', '1']
  357. self.assertEqual(actual, expected)
  358. class IterExceptTests(TestCase):
  359. """Tests for ``iter_except()``"""
  360. def test_exact_exception(self):
  361. """ensure the exact specified exception is caught"""
  362. l = [1, 2, 3]
  363. i = mi.iter_except(l.pop, IndexError)
  364. self.assertEqual(list(i), [3, 2, 1])
  365. def test_generic_exception(self):
  366. """ensure the generic exception can be caught"""
  367. l = [1, 2]
  368. i = mi.iter_except(l.pop, Exception)
  369. self.assertEqual(list(i), [2, 1])
  370. def test_uncaught_exception_is_raised(self):
  371. """ensure a non-specified exception is raised"""
  372. l = [1, 2, 3]
  373. i = mi.iter_except(l.pop, KeyError)
  374. self.assertRaises(IndexError, lambda: list(i))
  375. def test_first(self):
  376. """ensure first is run before the function"""
  377. l = [1, 2, 3]
  378. f = lambda: 25
  379. i = mi.iter_except(l.pop, IndexError, f)
  380. self.assertEqual(list(i), [25, 3, 2, 1])
  381. def test_multiple(self):
  382. """ensure can catch multiple exceptions"""
  383. class Fiz(Exception):
  384. pass
  385. class Buzz(Exception):
  386. pass
  387. i = 0
  388. def fizbuzz():
  389. nonlocal i
  390. i += 1
  391. if i % 3 == 0:
  392. raise Fiz
  393. if i % 5 == 0:
  394. raise Buzz
  395. return i
  396. expected = ([1, 2], [4], [], [7, 8], [])
  397. for x in expected:
  398. self.assertEqual(list(mi.iter_except(fizbuzz, (Fiz, Buzz))), x)
  399. class FirstTrueTests(TestCase):
  400. """Tests for ``first_true()``"""
  401. def test_something_true(self):
  402. """Test with no keywords"""
  403. self.assertEqual(mi.first_true(range(10)), 1)
  404. def test_nothing_true(self):
  405. """Test default return value."""
  406. self.assertIsNone(mi.first_true([0, 0, 0]))
  407. def test_default(self):
  408. """Test with a default keyword"""
  409. self.assertEqual(mi.first_true([0, 0, 0], default='!'), '!')
  410. def test_pred(self):
  411. """Test with a custom predicate"""
  412. self.assertEqual(
  413. mi.first_true([2, 4, 6], pred=lambda x: x % 3 == 0), 6
  414. )
  415. class RandomProductTests(TestCase):
  416. """Tests for ``random_product()``
  417. Since random.choice() has different results with the same seed across
  418. python versions 2.x and 3.x, these tests use highly probably events to
  419. create predictable outcomes across platforms.
  420. """
  421. def test_simple_lists(self):
  422. """Ensure that one item is chosen from each list in each pair.
  423. Also ensure that each item from each list eventually appears in
  424. the chosen combinations.
  425. Odds are roughly 1 in 7.1 * 10e16 that one item from either list will
  426. not be chosen after 100 samplings of one item from each list. Just to
  427. be safe, better use a known random seed, too.
  428. """
  429. nums = [1, 2, 3]
  430. lets = ['a', 'b', 'c']
  431. n, m = zip(*[mi.random_product(nums, lets) for _ in range(100)])
  432. n, m = set(n), set(m)
  433. self.assertEqual(n, set(nums))
  434. self.assertEqual(m, set(lets))
  435. self.assertEqual(len(n), len(nums))
  436. self.assertEqual(len(m), len(lets))
  437. def test_list_with_repeat(self):
  438. """ensure multiple items are chosen, and that they appear to be chosen
  439. from one list then the next, in proper order.
  440. """
  441. nums = [1, 2, 3]
  442. lets = ['a', 'b', 'c']
  443. r = list(mi.random_product(nums, lets, repeat=100))
  444. self.assertEqual(2 * 100, len(r))
  445. n, m = set(r[::2]), set(r[1::2])
  446. self.assertEqual(n, set(nums))
  447. self.assertEqual(m, set(lets))
  448. self.assertEqual(len(n), len(nums))
  449. self.assertEqual(len(m), len(lets))
  450. class RandomPermutationTests(TestCase):
  451. """Tests for ``random_permutation()``"""
  452. def test_full_permutation(self):
  453. """ensure every item from the iterable is returned in a new ordering
  454. 15 elements have a 1 in 1.3 * 10e12 of appearing in sorted order, so
  455. we fix a seed value just to be sure.
  456. """
  457. i = range(15)
  458. r = mi.random_permutation(i)
  459. self.assertEqual(set(i), set(r))
  460. if i == r:
  461. raise AssertionError("Values were not permuted")
  462. def test_partial_permutation(self):
  463. """ensure all returned items are from the iterable, that the returned
  464. permutation is of the desired length, and that all items eventually
  465. get returned.
  466. Sampling 100 permutations of length 5 from a set of 15 leaves a
  467. (2/3)^100 chance that an item will not be chosen. Multiplied by 15
  468. items, there is a 1 in 2.6e16 chance that at least 1 item will not
  469. show up in the resulting output. Using a random seed will fix that.
  470. """
  471. items = range(15)
  472. item_set = set(items)
  473. all_items = set()
  474. for _ in range(100):
  475. permutation = mi.random_permutation(items, 5)
  476. self.assertEqual(len(permutation), 5)
  477. permutation_set = set(permutation)
  478. self.assertLessEqual(permutation_set, item_set)
  479. all_items |= permutation_set
  480. self.assertEqual(all_items, item_set)
  481. class RandomCombinationTests(TestCase):
  482. """Tests for ``random_combination()``"""
  483. def test_pseudorandomness(self):
  484. """ensure different subsets of the iterable get returned over many
  485. samplings of random combinations"""
  486. items = range(15)
  487. all_items = set()
  488. for _ in range(50):
  489. combination = mi.random_combination(items, 5)
  490. all_items |= set(combination)
  491. self.assertEqual(all_items, set(items))
  492. def test_no_replacement(self):
  493. """ensure that elements are sampled without replacement"""
  494. items = range(15)
  495. for _ in range(50):
  496. combination = mi.random_combination(items, len(items))
  497. self.assertEqual(len(combination), len(set(combination)))
  498. self.assertRaises(
  499. ValueError, lambda: mi.random_combination(items, len(items) + 1)
  500. )
  501. class RandomCombinationWithReplacementTests(TestCase):
  502. """Tests for ``random_combination_with_replacement()``"""
  503. def test_replacement(self):
  504. """ensure that elements are sampled with replacement"""
  505. items = range(5)
  506. combo = mi.random_combination_with_replacement(items, len(items) * 2)
  507. self.assertEqual(2 * len(items), len(combo))
  508. if len(set(combo)) == len(combo):
  509. raise AssertionError("Combination contained no duplicates")
  510. def test_pseudorandomness(self):
  511. """ensure different subsets of the iterable get returned over many
  512. samplings of random combinations"""
  513. items = range(15)
  514. all_items = set()
  515. for _ in range(50):
  516. combination = mi.random_combination_with_replacement(items, 5)
  517. all_items |= set(combination)
  518. self.assertEqual(all_items, set(items))
  519. class NthCombinationTests(TestCase):
  520. def test_basic(self):
  521. iterable = 'abcdefg'
  522. r = 4
  523. for index, expected in enumerate(combinations(iterable, r)):
  524. actual = mi.nth_combination(iterable, r, index)
  525. self.assertEqual(actual, expected)
  526. def test_long(self):
  527. actual = mi.nth_combination(range(180), 4, 2000000)
  528. expected = (2, 12, 35, 126)
  529. self.assertEqual(actual, expected)
  530. def test_invalid_r(self):
  531. for r in (-1, 3):
  532. with self.assertRaises(ValueError):
  533. mi.nth_combination([], r, 0)
  534. def test_invalid_index(self):
  535. with self.assertRaises(IndexError):
  536. mi.nth_combination('abcdefg', 3, -36)
  537. class NthPermutationTests(TestCase):
  538. def test_r_less_than_n(self):
  539. iterable = 'abcde'
  540. r = 4
  541. for index, expected in enumerate(permutations(iterable, r)):
  542. actual = mi.nth_permutation(iterable, r, index)
  543. self.assertEqual(actual, expected)
  544. def test_r_equal_to_n(self):
  545. iterable = 'abcde'
  546. for index, expected in enumerate(permutations(iterable)):
  547. actual = mi.nth_permutation(iterable, None, index)
  548. self.assertEqual(actual, expected)
  549. def test_long(self):
  550. iterable = tuple(range(180))
  551. r = 4
  552. index = 1000000
  553. actual = mi.nth_permutation(iterable, r, index)
  554. expected = mi.nth(permutations(iterable, r), index)
  555. self.assertEqual(actual, expected)
  556. def test_null(self):
  557. actual = mi.nth_permutation([], 0, 0)
  558. expected = tuple()
  559. self.assertEqual(actual, expected)
  560. def test_negative_index(self):
  561. iterable = 'abcde'
  562. r = 4
  563. n = factorial(len(iterable)) // factorial(len(iterable) - r)
  564. for index, expected in enumerate(permutations(iterable, r)):
  565. actual = mi.nth_permutation(iterable, r, index - n)
  566. self.assertEqual(actual, expected)
  567. def test_invalid_index(self):
  568. iterable = 'abcde'
  569. r = 4
  570. n = factorial(len(iterable)) // factorial(len(iterable) - r)
  571. for index in [-1 - n, n + 1]:
  572. with self.assertRaises(IndexError):
  573. mi.nth_permutation(iterable, r, index)
  574. def test_invalid_r(self):
  575. iterable = 'abcde'
  576. r = 4
  577. n = factorial(len(iterable)) // factorial(len(iterable) - r)
  578. for r in [-1, n + 1]:
  579. with self.assertRaises(ValueError):
  580. mi.nth_permutation(iterable, r, 0)
  581. class PrependTests(TestCase):
  582. def test_basic(self):
  583. value = 'a'
  584. iterator = iter('bcdefg')
  585. actual = list(mi.prepend(value, iterator))
  586. expected = list('abcdefg')
  587. self.assertEqual(actual, expected)
  588. def test_multiple(self):
  589. value = 'ab'
  590. iterator = iter('cdefg')
  591. actual = tuple(mi.prepend(value, iterator))
  592. expected = ('ab',) + tuple('cdefg')
  593. self.assertEqual(actual, expected)
  594. class Convolvetests(TestCase):
  595. def test_moving_average(self):
  596. signal = iter([10, 20, 30, 40, 50])
  597. kernel = [0.5, 0.5]
  598. actual = list(mi.convolve(signal, kernel))
  599. expected = [
  600. (10 + 0) / 2,
  601. (20 + 10) / 2,
  602. (30 + 20) / 2,
  603. (40 + 30) / 2,
  604. (50 + 40) / 2,
  605. (0 + 50) / 2,
  606. ]
  607. self.assertEqual(actual, expected)
  608. def test_derivative(self):
  609. signal = iter([10, 20, 30, 40, 50])
  610. kernel = [1, -1]
  611. actual = list(mi.convolve(signal, kernel))
  612. expected = [10 - 0, 20 - 10, 30 - 20, 40 - 30, 50 - 40, 0 - 50]
  613. self.assertEqual(actual, expected)
  614. def test_infinite_signal(self):
  615. signal = count()
  616. kernel = [1, -1]
  617. actual = mi.take(5, mi.convolve(signal, kernel))
  618. expected = [0, 1, 1, 1, 1]
  619. self.assertEqual(actual, expected)
  620. class BeforeAndAfterTests(TestCase):
  621. def test_empty(self):
  622. before, after = mi.before_and_after(bool, [])
  623. self.assertEqual(list(before), [])
  624. self.assertEqual(list(after), [])
  625. def test_never_true(self):
  626. before, after = mi.before_and_after(bool, [0, False, None, ''])
  627. self.assertEqual(list(before), [])
  628. self.assertEqual(list(after), [0, False, None, ''])
  629. def test_never_false(self):
  630. before, after = mi.before_and_after(bool, [1, True, Ellipsis, ' '])
  631. self.assertEqual(list(before), [1, True, Ellipsis, ' '])
  632. self.assertEqual(list(after), [])
  633. def test_some_true(self):
  634. before, after = mi.before_and_after(bool, [1, True, 0, False])
  635. self.assertEqual(list(before), [1, True])
  636. self.assertEqual(list(after), [0, False])
  637. @staticmethod
  638. def _group_events(events):
  639. events = iter(events)
  640. while True:
  641. try:
  642. operation = next(events)
  643. except StopIteration:
  644. break
  645. assert operation in ["SUM", "MULTIPLY"]
  646. # Here, the remainder `events` is passed into `before_and_after`
  647. # again, which would be problematic if the remainder is a
  648. # generator function (as in Python 3.10 itertools recipes), since
  649. # that creates recursion. `itertools.chain` solves this problem.
  650. numbers, events = mi.before_and_after(
  651. lambda e: isinstance(e, int), events
  652. )
  653. yield (operation, numbers)
  654. def test_nested_remainder(self):
  655. events = ["SUM", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * 1000
  656. events += ["MULTIPLY", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * 1000
  657. for operation, numbers in self._group_events(events):
  658. if operation == "SUM":
  659. res = sum(numbers)
  660. self.assertEqual(res, 55)
  661. elif operation == "MULTIPLY":
  662. res = reduce(lambda a, b: a * b, numbers)
  663. self.assertEqual(res, 3628800)
  664. class TriplewiseTests(TestCase):
  665. def test_basic(self):
  666. for iterable, expected in [
  667. ([0], []),
  668. ([0, 1], []),
  669. ([0, 1, 2], [(0, 1, 2)]),
  670. ([0, 1, 2, 3], [(0, 1, 2), (1, 2, 3)]),
  671. ([0, 1, 2, 3, 4], [(0, 1, 2), (1, 2, 3), (2, 3, 4)]),
  672. ]:
  673. with self.subTest(expected=expected):
  674. actual = list(mi.triplewise(iterable))
  675. self.assertEqual(actual, expected)
  676. class SlidingWindowTests(TestCase):
  677. def test_islice_version(self):
  678. for iterable, n, expected in [
  679. ([], 1, []),
  680. ([0], 1, [(0,)]),
  681. ([0, 1], 1, [(0,), (1,)]),
  682. ([0, 1, 2], 2, [(0, 1), (1, 2)]),
  683. ([0, 1, 2], 3, [(0, 1, 2)]),
  684. ([0, 1, 2], 4, []),
  685. ([0, 1, 2, 3], 4, [(0, 1, 2, 3)]),
  686. ([0, 1, 2, 3, 4], 4, [(0, 1, 2, 3), (1, 2, 3, 4)]),
  687. ]:
  688. with self.subTest(expected=expected):
  689. actual = list(mi.sliding_window(iterable, n))
  690. self.assertEqual(actual, expected)
  691. def test_deque_version(self):
  692. iterable = map(str, range(100))
  693. all_windows = list(mi.sliding_window(iterable, 95))
  694. self.assertEqual(all_windows[0], tuple(map(str, range(95))))
  695. self.assertEqual(all_windows[-1], tuple(map(str, range(5, 100))))
  696. def test_zero(self):
  697. iterable = map(str, range(100))
  698. with self.assertRaises(ValueError):
  699. list(mi.sliding_window(iterable, 0))
  700. class SubslicesTests(TestCase):
  701. def test_basic(self):
  702. for iterable, expected in [
  703. ([], []),
  704. ([1], [[1]]),
  705. ([1, 2], [[1], [1, 2], [2]]),
  706. (iter([1, 2]), [[1], [1, 2], [2]]),
  707. ([2, 1], [[2], [2, 1], [1]]),
  708. (
  709. 'ABCD',
  710. [
  711. ['A'],
  712. ['A', 'B'],
  713. ['A', 'B', 'C'],
  714. ['A', 'B', 'C', 'D'],
  715. ['B'],
  716. ['B', 'C'],
  717. ['B', 'C', 'D'],
  718. ['C'],
  719. ['C', 'D'],
  720. ['D'],
  721. ],
  722. ),
  723. ]:
  724. with self.subTest(expected=expected):
  725. actual = list(mi.subslices(iterable))
  726. self.assertEqual(actual, expected)
  727. class PolynomialFromRootsTests(TestCase):
  728. def test_basic(self):
  729. for roots, expected in [
  730. ((2, 1, -1), [1, -2, -1, 2]),
  731. ((2, 3), [1, -5, 6]),
  732. ((1, 2, 3), [1, -6, 11, -6]),
  733. ((2, 4, 1), [1, -7, 14, -8]),
  734. ]:
  735. with self.subTest(roots=roots):
  736. actual = mi.polynomial_from_roots(roots)
  737. self.assertEqual(actual, expected)
  738. def test_large(self):
  739. n = 1_500
  740. actual = mi.polynomial_from_roots([-1] * n)
  741. expected = [comb(n, k) for k in range(n + 1)]
  742. self.assertEqual(actual, expected)
  743. class PolynomialEvalTests(TestCase):
  744. def test_basic(self):
  745. for coefficients, x, expected in [
  746. ([1, -4, -17, 60], 2, 18),
  747. ([1, -4, -17, 60], 2.5, 8.125),
  748. ([1, -4, -17, 60], Fraction(2, 3), Fraction(1274, 27)),
  749. ([1, -4, -17, 60], Decimal('1.75'), Decimal('23.359375')),
  750. ([], 2, 0),
  751. ([], 2.5, 0.0),
  752. ([], Fraction(2, 3), Fraction(0, 1)),
  753. ([], Decimal('1.75'), Decimal('0.00')),
  754. ([11], 7, 11),
  755. ([11, 2], 7, 79),
  756. ]:
  757. with self.subTest(x=x):
  758. actual = mi.polynomial_eval(coefficients, x)
  759. self.assertEqual(actual, expected)
  760. self.assertEqual(type(actual), type(x))
  761. class IterIndexTests(TestCase):
  762. def test_basic(self):
  763. iterable = 'AABCADEAF'
  764. for wrapper in (list, iter):
  765. with self.subTest(wrapper=wrapper):
  766. actual = list(mi.iter_index(wrapper(iterable), 'A'))
  767. expected = [0, 1, 4, 7]
  768. self.assertEqual(actual, expected)
  769. def test_start(self):
  770. for wrapper in (list, iter):
  771. with self.subTest(wrapper=wrapper):
  772. iterable = 'AABCADEAF'
  773. i = -1
  774. actual = []
  775. while True:
  776. try:
  777. i = next(
  778. mi.iter_index(wrapper(iterable), 'A', start=i + 1)
  779. )
  780. except StopIteration:
  781. break
  782. else:
  783. actual.append(i)
  784. expected = [0, 1, 4, 7]
  785. self.assertEqual(actual, expected)
  786. def test_stop(self):
  787. actual = list(mi.iter_index('AABCADEAF', 'A', stop=7))
  788. expected = [0, 1, 4]
  789. self.assertEqual(actual, expected)
  790. class SieveTests(TestCase):
  791. def test_basic(self):
  792. self.assertEqual(
  793. list(mi.sieve(67)),
  794. [
  795. 2,
  796. 3,
  797. 5,
  798. 7,
  799. 11,
  800. 13,
  801. 17,
  802. 19,
  803. 23,
  804. 29,
  805. 31,
  806. 37,
  807. 41,
  808. 43,
  809. 47,
  810. 53,
  811. 59,
  812. 61,
  813. ],
  814. )
  815. self.assertEqual(list(mi.sieve(68))[-1], 67)
  816. def test_prime_counts(self):
  817. for n, expected in (
  818. (100, 25),
  819. (1_000, 168),
  820. (10_000, 1229),
  821. (100_000, 9592),
  822. (1_000_000, 78498),
  823. ):
  824. with self.subTest(n=n):
  825. self.assertEqual(mi.ilen(mi.sieve(n)), expected)
  826. def test_small_numbers(self):
  827. with self.assertRaises(ValueError):
  828. list(mi.sieve(-1))
  829. for n in (0, 1, 2):
  830. with self.subTest(n=n):
  831. self.assertEqual(list(mi.sieve(n)), [])
  832. class BatchedTests(TestCase):
  833. def test_basic(self):
  834. iterable = range(1, 5 + 1)
  835. for n, expected in (
  836. (1, [(1,), (2,), (3,), (4,), (5,)]),
  837. (2, [(1, 2), (3, 4), (5,)]),
  838. (3, [(1, 2, 3), (4, 5)]),
  839. (4, [(1, 2, 3, 4), (5,)]),
  840. (5, [(1, 2, 3, 4, 5)]),
  841. (6, [(1, 2, 3, 4, 5)]),
  842. ):
  843. with self.subTest(n=n):
  844. actual = list(mi.batched(iterable, n))
  845. self.assertEqual(actual, expected)
  846. def test_strict(self):
  847. with self.assertRaises(ValueError):
  848. list(mi.batched('ABCDEFG', 3, strict=True))
  849. self.assertEqual(
  850. list(mi.batched('ABCDEF', 3, strict=True)),
  851. [('A', 'B', 'C'), ('D', 'E', 'F')],
  852. )
  853. class TransposeTests(TestCase):
  854. def test_empty(self):
  855. it = []
  856. actual = list(mi.transpose(it))
  857. expected = []
  858. self.assertEqual(actual, expected)
  859. def test_basic(self):
  860. it = [(10, 11, 12), (20, 21, 22), (30, 31, 32)]
  861. actual = list(mi.transpose(it))
  862. expected = [(10, 20, 30), (11, 21, 31), (12, 22, 32)]
  863. self.assertEqual(actual, expected)
  864. @skipIf(version_info[:2] < (3, 10), 'strict=True missing on 3.9')
  865. def test_incompatible_error(self):
  866. it = [(10, 11, 12, 13), (20, 21, 22), (30, 31, 32)]
  867. with self.assertRaises(ValueError):
  868. list(mi.transpose(it))
  869. @skipIf(version_info[:2] >= (3, 9), 'strict=True missing on 3.9')
  870. def test_incompatible_allow(self):
  871. it = [(10, 11, 12, 13), (20, 21, 22), (30, 31, 32)]
  872. actual = list(mi.transpose(it))
  873. expected = [(10, 20, 30), (11, 21, 31), (12, 22, 32)]
  874. self.assertEqual(actual, expected)
  875. class ReshapeTests(TestCase):
  876. def test_empty(self):
  877. actual = list(mi.reshape([], 3))
  878. self.assertEqual(actual, [])
  879. def test_zero(self):
  880. matrix = [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
  881. with self.assertRaises(ValueError):
  882. list(mi.reshape(matrix, 0))
  883. def test_basic(self):
  884. matrix = [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
  885. for cols, expected in (
  886. (
  887. 1,
  888. [
  889. (0,),
  890. (1,),
  891. (2,),
  892. (3,),
  893. (4,),
  894. (5,),
  895. (6,),
  896. (7,),
  897. (8,),
  898. (9,),
  899. (10,),
  900. (11,),
  901. ],
  902. ),
  903. (2, [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11)]),
  904. (3, [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11)]),
  905. (4, [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]),
  906. (6, [(0, 1, 2, 3, 4, 5), (6, 7, 8, 9, 10, 11)]),
  907. (12, [(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)]),
  908. ):
  909. with self.subTest(cols=cols):
  910. actual = list(mi.reshape(matrix, cols))
  911. self.assertEqual(actual, expected)
  912. class MatMulTests(TestCase):
  913. def test_n_by_n(self):
  914. actual = list(mi.matmul([(7, 5), (3, 5)], [[2, 5], [7, 9]]))
  915. expected = [(49, 80), (41, 60)]
  916. self.assertEqual(actual, expected)
  917. def test_m_by_n(self):
  918. m1 = [[2, 5], [7, 9], [3, 4]]
  919. m2 = [[7, 11, 5, 4, 9], [3, 5, 2, 6, 3]]
  920. actual = list(mi.matmul(m1, m2))
  921. expected = [
  922. (29, 47, 20, 38, 33),
  923. (76, 122, 53, 82, 90),
  924. (33, 53, 23, 36, 39),
  925. ]
  926. self.assertEqual(actual, expected)
  927. class FactorTests(TestCase):
  928. def test_basic(self):
  929. for n, expected in (
  930. (0, []),
  931. (1, []),
  932. (2, [2]),
  933. (3, [3]),
  934. (4, [2, 2]),
  935. (6, [2, 3]),
  936. (360, [2, 2, 2, 3, 3, 5]),
  937. (128_884_753_939, [128_884_753_939]),
  938. (999_953 * 999_983, [999_953, 999_983]),
  939. (909_909_090_909, [3, 3, 7, 13, 13, 751, 1_137_97]),
  940. (
  941. 1_647_403_876_764_101_672_307_088,
  942. [2, 2, 2, 2, 19, 23, 109471, 13571009, 158594251],
  943. ),
  944. ):
  945. with self.subTest(n=n):
  946. actual = list(mi.factor(n))
  947. self.assertEqual(actual, expected)
  948. def test_cross_check(self):
  949. prod = lambda x: reduce(mul, x, 1)
  950. self.assertTrue(all(prod(mi.factor(n)) == n for n in range(1, 2000)))
  951. self.assertTrue(
  952. all(set(mi.factor(n)) <= set(mi.sieve(n + 1)) for n in range(2000))
  953. )
  954. self.assertTrue(
  955. all(
  956. list(mi.factor(n)) == sorted(mi.factor(n)) for n in range(2000)
  957. )
  958. )
  959. class SumOfSquaresTests(TestCase):
  960. def test_basic(self):
  961. for it, expected in (
  962. ([], 0),
  963. ([1, 2, 3], 1 + 4 + 9),
  964. ([2, 4, 6, 8], 4 + 16 + 36 + 64),
  965. ):
  966. with self.subTest(it=it):
  967. actual = mi.sum_of_squares(it)
  968. self.assertEqual(actual, expected)
  969. class PolynomialDerivativeTests(TestCase):
  970. def test_basic(self):
  971. for coefficients, expected in [
  972. ([], []),
  973. ([1], []),
  974. ([1, 2], [1]),
  975. ([1, 2, 3], [2, 2]),
  976. ([1, 2, 3, 4], [3, 4, 3]),
  977. ([1.1, 2, 3, 4], [(1.1 * 3), 4, 3]),
  978. ]:
  979. with self.subTest(coefficients=coefficients):
  980. actual = mi.polynomial_derivative(coefficients)
  981. self.assertEqual(actual, expected)
  982. class TotientTests(TestCase):
  983. def test_basic(self):
  984. for n, expected in (
  985. (1, 1),
  986. (2, 1),
  987. (3, 2),
  988. (4, 2),
  989. (9, 6),
  990. (12, 4),
  991. (128_884_753_939, 128_884_753_938),
  992. (999953 * 999983, 999952 * 999982),
  993. (6**20, 1 * 2**19 * 2 * 3**19),
  994. ):
  995. with self.subTest(n=n):
  996. self.assertEqual(mi.totient(n), expected)
  997. class PrimeFunctionTests(TestCase):
  998. def test_is_prime_pseudoprimes(self):
  999. # Carmichael number that strong pseudoprime to prime bases < 307
  1000. # https://doi.org/10.1006/jsco.1995.1042
  1001. p = 29674495668685510550154174642905332730771991799853043350995075531276838753171770199594238596428121188033664754218345562493168782883 # noqa:E501
  1002. gnarly_carmichael = (313 * (p - 1) + 1) * (353 * (p - 1) + 1)
  1003. for n in (
  1004. # Least Carmichael number with n prime factors:
  1005. # https://oeis.org/A006931
  1006. 561,
  1007. 41041,
  1008. 825265,
  1009. 321197185,
  1010. 5394826801,
  1011. 232250619601,
  1012. 9746347772161,
  1013. 1436697831295441,
  1014. 60977817398996785,
  1015. 7156857700403137441,
  1016. 1791562810662585767521,
  1017. 87674969936234821377601,
  1018. 6553130926752006031481761,
  1019. 1590231231043178376951698401,
  1020. # Carmichael numbers with exactly 4 prime factors:
  1021. # https://oeis.org/A074379
  1022. 41041,
  1023. 62745,
  1024. 63973,
  1025. 75361,
  1026. 101101,
  1027. 126217,
  1028. 172081,
  1029. 188461,
  1030. 278545,
  1031. 340561,
  1032. 449065,
  1033. 552721,
  1034. 656601,
  1035. 658801,
  1036. 670033,
  1037. 748657,
  1038. 838201,
  1039. 852841,
  1040. 997633,
  1041. 1033669,
  1042. 1082809,
  1043. 1569457,
  1044. 1773289,
  1045. 2100901,
  1046. 2113921,
  1047. 2433601,
  1048. 2455921,
  1049. # Lucas-Carmichael numbers:
  1050. # https://oeis.org/A006972
  1051. 399,
  1052. 935,
  1053. 2015,
  1054. 2915,
  1055. 4991,
  1056. 5719,
  1057. 7055,
  1058. 8855,
  1059. 12719,
  1060. 18095,
  1061. 20705,
  1062. 20999,
  1063. 22847,
  1064. 29315,
  1065. 31535,
  1066. 46079,
  1067. 51359,
  1068. 60059,
  1069. 63503,
  1070. 67199,
  1071. 73535,
  1072. 76751,
  1073. 80189,
  1074. 81719,
  1075. 88559,
  1076. 90287,
  1077. # Strong pseudoprimes to bases 2, 3 and 5:
  1078. # https://oeis.org/A056915
  1079. 25326001,
  1080. 161304001,
  1081. 960946321,
  1082. 1157839381,
  1083. 3215031751,
  1084. 3697278427,
  1085. 5764643587,
  1086. 6770862367,
  1087. 14386156093,
  1088. 15579919981,
  1089. 18459366157,
  1090. 19887974881,
  1091. 21276028621,
  1092. 27716349961,
  1093. 29118033181,
  1094. 37131467521,
  1095. 41752650241,
  1096. 42550716781,
  1097. 43536545821,
  1098. # Strong pseudoprimes to bases 2, 3, 5, and 7:
  1099. # https://oeis.org/A211112
  1100. 39365185894561,
  1101. 52657210792621,
  1102. 11377272352951,
  1103. 15070413782971,
  1104. 3343433905957,
  1105. 16603327018981,
  1106. 3461715915661,
  1107. 52384617784801,
  1108. 3477707481751,
  1109. 18996486073489,
  1110. 55712149574381,
  1111. gnarly_carmichael,
  1112. ):
  1113. with self.subTest(n=n):
  1114. self.assertFalse(mi.is_prime(n))
  1115. def test_primes(self):
  1116. for i, n in enumerate(mi.sieve(10**5)):
  1117. with self.subTest(n=n):
  1118. self.assertTrue(mi.is_prime(n))
  1119. self.assertEqual(mi.nth_prime(i), n)
  1120. self.assertFalse(mi.is_prime(-1))
  1121. with self.assertRaises(ValueError):
  1122. mi.nth_prime(-1)
  1123. def test_special_primes(self):
  1124. for n in (
  1125. # Mersenee primes:
  1126. # https://oeis.org/A211112
  1127. 3,
  1128. 7,
  1129. 31,
  1130. 127,
  1131. 8191,
  1132. 131071,
  1133. 524287,
  1134. 2147483647,
  1135. 2305843009213693951,
  1136. 618970019642690137449562111,
  1137. 162259276829213363391578010288127,
  1138. 170141183460469231731687303715884105727,
  1139. # Various big primes:
  1140. # https://bigprimes.org/
  1141. 7990614013,
  1142. 80358337843874809987,
  1143. 814847562949580526031364519741,
  1144. 1982427225022428178169740526258124929077,
  1145. 91828213828508622559862344537590739566883686537727,
  1146. 406414746815201693481517584049440077164779143248351060891669,
  1147. ):
  1148. with self.subTest(n=n):
  1149. self.assertTrue(mi.is_prime(n))
  1150. class LoopsTests(TestCase):
  1151. def test_basic(self):
  1152. self.assertTrue(
  1153. all(list(mi.loops(n)) == [None] * n for n in range(-10, 10))
  1154. )