numclassify 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- numclassify/__init__.py +63 -0
- numclassify/__main__.py +4 -0
- numclassify/_core/__init__.py +0 -0
- numclassify/_core/combinatorial.py +392 -0
- numclassify/_core/digital.py +403 -0
- numclassify/_core/divisors.py +756 -0
- numclassify/_core/figurate.py +357 -0
- numclassify/_core/number_theory.py +533 -0
- numclassify/_core/powers.py +349 -0
- numclassify/_core/primes.py +2100 -0
- numclassify/_core/recreational.py +245 -0
- numclassify/_core/sequences.py +488 -0
- numclassify/_registry.py +417 -0
- numclassify/cli.py +525 -0
- numclassify-0.1.0.dist-info/METADATA +220 -0
- numclassify-0.1.0.dist-info/RECORD +19 -0
- numclassify-0.1.0.dist-info/WHEEL +4 -0
- numclassify-0.1.0.dist-info/entry_points.txt +2 -0
- numclassify-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,2100 @@
|
|
|
1
|
+
"""
|
|
2
|
+
numclassify._core.primes
|
|
3
|
+
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
4
|
+
Prime-number classification functions.
|
|
5
|
+
|
|
6
|
+
All functions are registered in the global registry via ``@register`` and are
|
|
7
|
+
also available as plain module-level callables so other modules can import them
|
|
8
|
+
directly (e.g. ``from numclassify._core.primes import is_prime``).
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import math
|
|
14
|
+
import itertools
|
|
15
|
+
from typing import List
|
|
16
|
+
|
|
17
|
+
from numclassify._registry import register
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
# Miller-Rabin primality test (deterministic for n < 3_215_031_751,
|
|
22
|
+
# probabilistic with 20 rounds for larger values)
|
|
23
|
+
# ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
def _miller_rabin_test(n: int, witnesses: List[int]) -> bool:
|
|
26
|
+
"""Return ``True`` if *n* passes Miller-Rabin for all *witnesses*.
|
|
27
|
+
|
|
28
|
+
Writes *n-1* as ``2^r * d`` then checks each witness *a*.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
n:
|
|
33
|
+
Odd integer > 2 to test.
|
|
34
|
+
witnesses:
|
|
35
|
+
List of bases to use.
|
|
36
|
+
"""
|
|
37
|
+
r, d = 0, n - 1
|
|
38
|
+
while d % 2 == 0:
|
|
39
|
+
r += 1
|
|
40
|
+
d //= 2
|
|
41
|
+
|
|
42
|
+
for a in witnesses:
|
|
43
|
+
if a >= n:
|
|
44
|
+
continue
|
|
45
|
+
x = pow(a, d, n)
|
|
46
|
+
if x == 1 or x == n - 1:
|
|
47
|
+
continue
|
|
48
|
+
for _ in range(r - 1):
|
|
49
|
+
x = pow(x, 2, n)
|
|
50
|
+
if x == n - 1:
|
|
51
|
+
break
|
|
52
|
+
else:
|
|
53
|
+
return False
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
# Helper functions (not registered, used internally)
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
def primes_up_to(n: int) -> List[int]:
|
|
62
|
+
"""Return a list of all primes <= *n* via the Sieve of Eratosthenes.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
n:
|
|
67
|
+
Upper bound (inclusive).
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
list[int]
|
|
72
|
+
|
|
73
|
+
Example
|
|
74
|
+
-------
|
|
75
|
+
>>> primes_up_to(20)
|
|
76
|
+
[2, 3, 5, 7, 11, 13, 17, 19]
|
|
77
|
+
"""
|
|
78
|
+
if n < 2:
|
|
79
|
+
return []
|
|
80
|
+
sieve = bytearray([1]) * (n + 1)
|
|
81
|
+
sieve[0] = sieve[1] = 0
|
|
82
|
+
for i in range(2, int(n ** 0.5) + 1):
|
|
83
|
+
if sieve[i]:
|
|
84
|
+
sieve[i * i :: i] = bytearray(len(sieve[i * i :: i]))
|
|
85
|
+
return [i for i, v in enumerate(sieve) if v]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def prime_factors(n: int) -> List[int]:
|
|
89
|
+
"""Return the full prime factorisation of *n* with repetition.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
n:
|
|
94
|
+
Integer >= 2 to factorise.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
list[int]
|
|
99
|
+
Sorted list of prime factors including multiplicity.
|
|
100
|
+
|
|
101
|
+
Example
|
|
102
|
+
-------
|
|
103
|
+
>>> prime_factors(12)
|
|
104
|
+
[2, 2, 3]
|
|
105
|
+
>>> prime_factors(360)
|
|
106
|
+
[2, 2, 2, 3, 3, 5]
|
|
107
|
+
"""
|
|
108
|
+
factors: List[int] = []
|
|
109
|
+
if n < 2:
|
|
110
|
+
return factors
|
|
111
|
+
d = 2
|
|
112
|
+
while d * d <= n:
|
|
113
|
+
while n % d == 0:
|
|
114
|
+
factors.append(d)
|
|
115
|
+
n //= d
|
|
116
|
+
d += 1
|
|
117
|
+
if n > 1:
|
|
118
|
+
factors.append(n)
|
|
119
|
+
return factors
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def prev_prime(n: int) -> int:
|
|
123
|
+
"""Return the largest prime strictly less than *n*.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
n:
|
|
128
|
+
Integer > 2.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
int
|
|
133
|
+
|
|
134
|
+
Example
|
|
135
|
+
-------
|
|
136
|
+
>>> prev_prime(10)
|
|
137
|
+
7
|
|
138
|
+
>>> prev_prime(3)
|
|
139
|
+
2
|
|
140
|
+
"""
|
|
141
|
+
if n <= 2:
|
|
142
|
+
raise ValueError("No prime less than 2")
|
|
143
|
+
candidate = n - 1
|
|
144
|
+
while candidate >= 2:
|
|
145
|
+
if is_prime(candidate):
|
|
146
|
+
return candidate
|
|
147
|
+
candidate -= 1
|
|
148
|
+
raise ValueError(f"No prime found below {n}")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def next_prime(n: int) -> int:
|
|
152
|
+
"""Return the smallest prime strictly greater than *n*.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
n:
|
|
157
|
+
Non-negative integer.
|
|
158
|
+
|
|
159
|
+
Returns
|
|
160
|
+
-------
|
|
161
|
+
int
|
|
162
|
+
|
|
163
|
+
Example
|
|
164
|
+
-------
|
|
165
|
+
>>> next_prime(10)
|
|
166
|
+
11
|
|
167
|
+
>>> next_prime(1)
|
|
168
|
+
2
|
|
169
|
+
"""
|
|
170
|
+
candidate = max(n + 1, 2)
|
|
171
|
+
while True:
|
|
172
|
+
if is_prime(candidate):
|
|
173
|
+
return candidate
|
|
174
|
+
candidate += 1
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# ---------------------------------------------------------------------------
|
|
178
|
+
# Existing 5 functions — kept exactly as-is
|
|
179
|
+
# ---------------------------------------------------------------------------
|
|
180
|
+
|
|
181
|
+
@register(
|
|
182
|
+
name="Prime",
|
|
183
|
+
category="primes",
|
|
184
|
+
oeis="A000040",
|
|
185
|
+
description=(
|
|
186
|
+
"A natural number greater than 1 with no positive divisors other than "
|
|
187
|
+
"1 and itself."
|
|
188
|
+
),
|
|
189
|
+
)
|
|
190
|
+
def is_prime(n: int) -> bool:
|
|
191
|
+
"""Return ``True`` if *n* is a prime number.
|
|
192
|
+
|
|
193
|
+
Uses a deterministic Miller-Rabin test with witnesses ``[2, 3, 5, 7]``
|
|
194
|
+
for *n* < 3,215,031,751. For larger values, 20 additional random-free
|
|
195
|
+
witnesses ``[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
|
|
196
|
+
59, 61, 67, 71]`` are used, which is deterministic up to at least 3.3 × 10²⁴.
|
|
197
|
+
|
|
198
|
+
Correctly rejects Carmichael numbers such as 561.
|
|
199
|
+
|
|
200
|
+
Parameters
|
|
201
|
+
----------
|
|
202
|
+
n:
|
|
203
|
+
Integer to test.
|
|
204
|
+
|
|
205
|
+
Returns
|
|
206
|
+
-------
|
|
207
|
+
bool
|
|
208
|
+
|
|
209
|
+
Example
|
|
210
|
+
-------
|
|
211
|
+
>>> is_prime(2)
|
|
212
|
+
True
|
|
213
|
+
>>> is_prime(561) # Carmichael number — composite
|
|
214
|
+
False
|
|
215
|
+
>>> is_prime(1_000_000_007)
|
|
216
|
+
True
|
|
217
|
+
"""
|
|
218
|
+
if n < 2:
|
|
219
|
+
return False
|
|
220
|
+
if n == 2:
|
|
221
|
+
return True
|
|
222
|
+
if n % 2 == 0:
|
|
223
|
+
return False
|
|
224
|
+
if n < 9:
|
|
225
|
+
return True
|
|
226
|
+
if n % 3 == 0:
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
if n < 3_215_031_751:
|
|
230
|
+
witnesses = [2, 3, 5, 7]
|
|
231
|
+
else:
|
|
232
|
+
witnesses = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
|
|
233
|
+
41, 43, 47, 53, 59, 61, 67, 71]
|
|
234
|
+
|
|
235
|
+
return _miller_rabin_test(n, witnesses)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@register(
|
|
239
|
+
name="Twin Prime",
|
|
240
|
+
category="primes",
|
|
241
|
+
oeis="A001097",
|
|
242
|
+
description=(
|
|
243
|
+
"A prime p such that p − 2 or p + 2 is also prime "
|
|
244
|
+
"(i.e. p is part of a twin-prime pair)."
|
|
245
|
+
),
|
|
246
|
+
aliases=["twin_prime"],
|
|
247
|
+
)
|
|
248
|
+
def is_twin_prime(n: int) -> bool:
|
|
249
|
+
"""Return ``True`` if *n* is a twin prime.
|
|
250
|
+
|
|
251
|
+
A twin prime is a prime *p* for which *p − 2* or *p + 2* is also prime.
|
|
252
|
+
|
|
253
|
+
Parameters
|
|
254
|
+
----------
|
|
255
|
+
n:
|
|
256
|
+
Integer to test.
|
|
257
|
+
|
|
258
|
+
Returns
|
|
259
|
+
-------
|
|
260
|
+
bool
|
|
261
|
+
|
|
262
|
+
Example
|
|
263
|
+
-------
|
|
264
|
+
>>> is_twin_prime(5) # 3 and 7 are both prime
|
|
265
|
+
True
|
|
266
|
+
>>> is_twin_prime(23) # 21=3*7 composite, 25=5² composite
|
|
267
|
+
False
|
|
268
|
+
"""
|
|
269
|
+
if not is_prime(n):
|
|
270
|
+
return False
|
|
271
|
+
return is_prime(n - 2) or is_prime(n + 2)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
@register(
|
|
275
|
+
name="Mersenne Prime",
|
|
276
|
+
category="primes",
|
|
277
|
+
oeis="A000668",
|
|
278
|
+
description=(
|
|
279
|
+
"A prime of the form 2^p − 1 where p itself is prime."
|
|
280
|
+
),
|
|
281
|
+
aliases=["mersenne_prime"],
|
|
282
|
+
)
|
|
283
|
+
def is_mersenne_prime(n: int) -> bool:
|
|
284
|
+
"""Return ``True`` if *n* is a Mersenne prime.
|
|
285
|
+
|
|
286
|
+
A Mersenne prime has the form 2^p − 1 where *p* is prime. This
|
|
287
|
+
implementation checks that *n* + 1 is a power of 2 and that the
|
|
288
|
+
corresponding exponent is prime, then verifies *n* itself is prime.
|
|
289
|
+
|
|
290
|
+
Parameters
|
|
291
|
+
----------
|
|
292
|
+
n:
|
|
293
|
+
Integer to test.
|
|
294
|
+
|
|
295
|
+
Returns
|
|
296
|
+
-------
|
|
297
|
+
bool
|
|
298
|
+
|
|
299
|
+
Example
|
|
300
|
+
-------
|
|
301
|
+
>>> is_mersenne_prime(7) # 2^3 - 1 = 7, 3 is prime
|
|
302
|
+
True
|
|
303
|
+
>>> is_mersenne_prime(15) # 2^4 - 1 = 15, 4 is not prime
|
|
304
|
+
False
|
|
305
|
+
"""
|
|
306
|
+
if n < 2:
|
|
307
|
+
return False
|
|
308
|
+
m = n + 1
|
|
309
|
+
if m & (m - 1) != 0:
|
|
310
|
+
return False
|
|
311
|
+
p = m.bit_length() - 1
|
|
312
|
+
return is_prime(p) and is_prime(n)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
@register(
|
|
316
|
+
name="Sophie Germain Prime",
|
|
317
|
+
category="primes",
|
|
318
|
+
oeis="A005384",
|
|
319
|
+
description=(
|
|
320
|
+
"A prime p such that 2p + 1 is also prime."
|
|
321
|
+
),
|
|
322
|
+
aliases=["sophie_germain_prime", "sophie germain prime"],
|
|
323
|
+
)
|
|
324
|
+
def is_sophie_germain_prime(n: int) -> bool:
|
|
325
|
+
"""Return ``True`` if *n* is a Sophie Germain prime.
|
|
326
|
+
|
|
327
|
+
A Sophie Germain prime is a prime *p* for which ``2p + 1`` is also prime.
|
|
328
|
+
The prime ``2p + 1`` is called a *safe prime*.
|
|
329
|
+
|
|
330
|
+
Parameters
|
|
331
|
+
----------
|
|
332
|
+
n:
|
|
333
|
+
Integer to test.
|
|
334
|
+
|
|
335
|
+
Returns
|
|
336
|
+
-------
|
|
337
|
+
bool
|
|
338
|
+
|
|
339
|
+
Example
|
|
340
|
+
-------
|
|
341
|
+
>>> is_sophie_germain_prime(11) # 2*11+1=23, prime
|
|
342
|
+
True
|
|
343
|
+
>>> is_sophie_germain_prime(13) # 2*13+1=27=3^3, composite
|
|
344
|
+
False
|
|
345
|
+
"""
|
|
346
|
+
return is_prime(n) and is_prime(2 * n + 1)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
@register(
|
|
350
|
+
name="Safe Prime",
|
|
351
|
+
category="primes",
|
|
352
|
+
oeis="A005385",
|
|
353
|
+
description=(
|
|
354
|
+
"A prime p such that (p − 1) / 2 is also prime."
|
|
355
|
+
),
|
|
356
|
+
aliases=["safe_prime"],
|
|
357
|
+
)
|
|
358
|
+
def is_safe_prime(n: int) -> bool:
|
|
359
|
+
"""Return ``True`` if *n* is a safe prime.
|
|
360
|
+
|
|
361
|
+
A safe prime is a prime *p* for which ``(p − 1) / 2`` is also prime.
|
|
362
|
+
Safe primes are related to Sophie Germain primes: *p* is safe iff
|
|
363
|
+
``(p − 1) / 2`` is a Sophie Germain prime.
|
|
364
|
+
|
|
365
|
+
Parameters
|
|
366
|
+
----------
|
|
367
|
+
n:
|
|
368
|
+
Integer to test.
|
|
369
|
+
|
|
370
|
+
Returns
|
|
371
|
+
-------
|
|
372
|
+
bool
|
|
373
|
+
|
|
374
|
+
Example
|
|
375
|
+
-------
|
|
376
|
+
>>> is_safe_prime(23) # (23-1)/2 = 11, prime
|
|
377
|
+
True
|
|
378
|
+
>>> is_safe_prime(7) # (7-1)/2 = 3, prime
|
|
379
|
+
True
|
|
380
|
+
>>> is_safe_prime(11) # (11-1)/2 = 5, prime
|
|
381
|
+
True
|
|
382
|
+
>>> is_safe_prime(13) # (13-1)/2 = 6, composite
|
|
383
|
+
False
|
|
384
|
+
"""
|
|
385
|
+
if not is_prime(n):
|
|
386
|
+
return False
|
|
387
|
+
if (n - 1) % 2 != 0:
|
|
388
|
+
return False
|
|
389
|
+
return is_prime((n - 1) // 2)
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
# ---------------------------------------------------------------------------
|
|
393
|
+
# GROUP 1 — Form-based primes
|
|
394
|
+
# ---------------------------------------------------------------------------
|
|
395
|
+
|
|
396
|
+
@register(
|
|
397
|
+
name="Fermat Prime",
|
|
398
|
+
category="primes",
|
|
399
|
+
oeis="A019434",
|
|
400
|
+
description=(
|
|
401
|
+
"A prime of the form 2^(2^n) + 1. Only five are known: "
|
|
402
|
+
"3, 5, 17, 257, 65537."
|
|
403
|
+
),
|
|
404
|
+
aliases=["fermat_prime"],
|
|
405
|
+
)
|
|
406
|
+
def is_fermat_prime(n: int) -> bool:
|
|
407
|
+
"""Return ``True`` if *n* is a Fermat prime.
|
|
408
|
+
|
|
409
|
+
A Fermat prime is a prime of the form ``2^(2^k) + 1`` for some non-negative
|
|
410
|
+
integer *k*. Only five Fermat primes are currently known: 3, 5, 17, 257,
|
|
411
|
+
and 65537. This function checks membership in that known set.
|
|
412
|
+
|
|
413
|
+
Parameters
|
|
414
|
+
----------
|
|
415
|
+
n:
|
|
416
|
+
Integer to test.
|
|
417
|
+
|
|
418
|
+
Returns
|
|
419
|
+
-------
|
|
420
|
+
bool
|
|
421
|
+
|
|
422
|
+
Example
|
|
423
|
+
-------
|
|
424
|
+
>>> is_fermat_prime(17)
|
|
425
|
+
True
|
|
426
|
+
>>> is_fermat_prime(257)
|
|
427
|
+
True
|
|
428
|
+
>>> is_fermat_prime(7)
|
|
429
|
+
False
|
|
430
|
+
|
|
431
|
+
Notes
|
|
432
|
+
-----
|
|
433
|
+
No Fermat prime beyond 65537 has ever been found, and all Fermat numbers
|
|
434
|
+
``F_5`` through ``F_32`` have been shown to be composite.
|
|
435
|
+
"""
|
|
436
|
+
return n in {3, 5, 17, 257, 65537}
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
@register(
|
|
440
|
+
name="Factorial Prime",
|
|
441
|
+
category="primes",
|
|
442
|
+
oeis="A088054",
|
|
443
|
+
description=(
|
|
444
|
+
"A prime of the form n! + 1 or n! − 1 for some positive integer n."
|
|
445
|
+
),
|
|
446
|
+
aliases=["factorial_prime"],
|
|
447
|
+
)
|
|
448
|
+
def is_factorial_prime(n: int) -> bool:
|
|
449
|
+
"""Return ``True`` if *n* is a factorial prime.
|
|
450
|
+
|
|
451
|
+
A factorial prime has the form ``k! + 1`` or ``k! − 1`` for some positive
|
|
452
|
+
integer *k*. This implementation tests values of *k* starting at 1 and
|
|
453
|
+
stops once ``k!`` exceeds *n* + 1 (since further factorials can only grow).
|
|
454
|
+
|
|
455
|
+
Parameters
|
|
456
|
+
----------
|
|
457
|
+
n:
|
|
458
|
+
Integer to test.
|
|
459
|
+
|
|
460
|
+
Returns
|
|
461
|
+
-------
|
|
462
|
+
bool
|
|
463
|
+
|
|
464
|
+
Example
|
|
465
|
+
-------
|
|
466
|
+
>>> is_factorial_prime(5) # 3! - 1 = 5
|
|
467
|
+
True
|
|
468
|
+
>>> is_factorial_prime(7) # 3! + 1 = 7
|
|
469
|
+
True
|
|
470
|
+
>>> is_factorial_prime(23) # 4! - 1 = 23
|
|
471
|
+
True
|
|
472
|
+
>>> is_factorial_prime(11)
|
|
473
|
+
False
|
|
474
|
+
|
|
475
|
+
Edge cases
|
|
476
|
+
----------
|
|
477
|
+
* ``n <= 1`` returns ``False``.
|
|
478
|
+
"""
|
|
479
|
+
if n <= 1:
|
|
480
|
+
return False
|
|
481
|
+
if not is_prime(n):
|
|
482
|
+
return False
|
|
483
|
+
factorial = 1
|
|
484
|
+
k = 1
|
|
485
|
+
while True:
|
|
486
|
+
factorial *= k
|
|
487
|
+
if factorial - 1 == n or factorial + 1 == n:
|
|
488
|
+
return True
|
|
489
|
+
if factorial > n + 1:
|
|
490
|
+
break
|
|
491
|
+
k += 1
|
|
492
|
+
return False
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
@register(
|
|
496
|
+
name="Primorial Prime",
|
|
497
|
+
category="primes",
|
|
498
|
+
oeis="A057704",
|
|
499
|
+
description=(
|
|
500
|
+
"A prime of the form p# + 1 or p# − 1, where p# is the primorial "
|
|
501
|
+
"(product of all primes up to p)."
|
|
502
|
+
),
|
|
503
|
+
aliases=["primorial_prime"],
|
|
504
|
+
)
|
|
505
|
+
def is_primorial_prime(n: int) -> bool:
|
|
506
|
+
"""Return ``True`` if *n* is a primorial prime.
|
|
507
|
+
|
|
508
|
+
A primorial prime has the form ``p# + 1`` or ``p# − 1`` where ``p#``
|
|
509
|
+
denotes the product of all primes up to and including *p*.
|
|
510
|
+
|
|
511
|
+
Parameters
|
|
512
|
+
----------
|
|
513
|
+
n:
|
|
514
|
+
Integer to test.
|
|
515
|
+
|
|
516
|
+
Returns
|
|
517
|
+
-------
|
|
518
|
+
bool
|
|
519
|
+
|
|
520
|
+
Example
|
|
521
|
+
-------
|
|
522
|
+
>>> is_primorial_prime(5) # 2*3 - 1 = 5
|
|
523
|
+
True
|
|
524
|
+
>>> is_primorial_prime(7) # 2*3 + 1 = 7
|
|
525
|
+
True
|
|
526
|
+
>>> is_primorial_prime(29) # 2*3*5 - 1 = 29
|
|
527
|
+
True
|
|
528
|
+
>>> is_primorial_prime(31) # 2*3*5 + 1 = 31
|
|
529
|
+
True
|
|
530
|
+
>>> is_primorial_prime(11)
|
|
531
|
+
False
|
|
532
|
+
|
|
533
|
+
Edge cases
|
|
534
|
+
----------
|
|
535
|
+
* ``n <= 1`` returns ``False``.
|
|
536
|
+
"""
|
|
537
|
+
if n <= 1:
|
|
538
|
+
return False
|
|
539
|
+
if not is_prime(n):
|
|
540
|
+
return False
|
|
541
|
+
primorial = 1
|
|
542
|
+
for p in primes_up_to(n + 1):
|
|
543
|
+
primorial *= p
|
|
544
|
+
if primorial - 1 == n or primorial + 1 == n:
|
|
545
|
+
return True
|
|
546
|
+
if primorial > n + 1:
|
|
547
|
+
break
|
|
548
|
+
return False
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
@register(
|
|
552
|
+
name="Cullen Prime",
|
|
553
|
+
category="primes",
|
|
554
|
+
oeis="A050920",
|
|
555
|
+
description=(
|
|
556
|
+
"A prime of the form n·2^n + 1 for some positive integer n."
|
|
557
|
+
),
|
|
558
|
+
aliases=["cullen_prime"],
|
|
559
|
+
)
|
|
560
|
+
def is_cullen_prime(n: int) -> bool:
|
|
561
|
+
"""Return ``True`` if *n* is a Cullen prime.
|
|
562
|
+
|
|
563
|
+
A Cullen prime has the form ``k * 2^k + 1`` for some positive integer *k*.
|
|
564
|
+
The function iterates *k* from 1 upward until ``k * 2^k + 1`` exceeds *n*.
|
|
565
|
+
|
|
566
|
+
Parameters
|
|
567
|
+
----------
|
|
568
|
+
n:
|
|
569
|
+
Integer to test.
|
|
570
|
+
|
|
571
|
+
Returns
|
|
572
|
+
-------
|
|
573
|
+
bool
|
|
574
|
+
|
|
575
|
+
Example
|
|
576
|
+
-------
|
|
577
|
+
>>> is_cullen_prime(3) # 1*2^1 + 1 = 3
|
|
578
|
+
True
|
|
579
|
+
>>> is_cullen_prime(393050634124102232869567034555427371542904833)
|
|
580
|
+
False # too large; practical limit applies
|
|
581
|
+
|
|
582
|
+
Notes
|
|
583
|
+
-----
|
|
584
|
+
Known Cullen primes are sparse; the first few correspond to k = 1, 141, 4713, …
|
|
585
|
+
|
|
586
|
+
Edge cases
|
|
587
|
+
----------
|
|
588
|
+
* ``n <= 1`` returns ``False``.
|
|
589
|
+
"""
|
|
590
|
+
if n <= 1:
|
|
591
|
+
return False
|
|
592
|
+
if not is_prime(n):
|
|
593
|
+
return False
|
|
594
|
+
k = 1
|
|
595
|
+
while True:
|
|
596
|
+
cullen = k * (2 ** k) + 1
|
|
597
|
+
if cullen == n:
|
|
598
|
+
return True
|
|
599
|
+
if cullen > n:
|
|
600
|
+
break
|
|
601
|
+
k += 1
|
|
602
|
+
return False
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
@register(
|
|
606
|
+
name="Woodall Prime",
|
|
607
|
+
category="primes",
|
|
608
|
+
oeis="A050918",
|
|
609
|
+
description=(
|
|
610
|
+
"A prime of the form n·2^n − 1 for some positive integer n."
|
|
611
|
+
),
|
|
612
|
+
aliases=["woodall_prime"],
|
|
613
|
+
)
|
|
614
|
+
def is_woodall_prime(n: int) -> bool:
|
|
615
|
+
"""Return ``True`` if *n* is a Woodall prime.
|
|
616
|
+
|
|
617
|
+
A Woodall prime has the form ``k * 2^k − 1`` for some positive integer *k*.
|
|
618
|
+
The function iterates *k* from 1 upward until ``k * 2^k − 1`` exceeds *n*.
|
|
619
|
+
|
|
620
|
+
Parameters
|
|
621
|
+
----------
|
|
622
|
+
n:
|
|
623
|
+
Integer to test.
|
|
624
|
+
|
|
625
|
+
Returns
|
|
626
|
+
-------
|
|
627
|
+
bool
|
|
628
|
+
|
|
629
|
+
Example
|
|
630
|
+
-------
|
|
631
|
+
>>> is_woodall_prime(7) # 2*2^2 - 1 = 7
|
|
632
|
+
True
|
|
633
|
+
>>> is_woodall_prime(23) # 3*2^3 - 1 = 23
|
|
634
|
+
True
|
|
635
|
+
>>> is_woodall_prime(11)
|
|
636
|
+
False
|
|
637
|
+
|
|
638
|
+
Edge cases
|
|
639
|
+
----------
|
|
640
|
+
* ``n <= 1`` returns ``False``.
|
|
641
|
+
"""
|
|
642
|
+
if n <= 1:
|
|
643
|
+
return False
|
|
644
|
+
if not is_prime(n):
|
|
645
|
+
return False
|
|
646
|
+
k = 1
|
|
647
|
+
while True:
|
|
648
|
+
woodall = k * (2 ** k) - 1
|
|
649
|
+
if woodall == n:
|
|
650
|
+
return True
|
|
651
|
+
if woodall > n:
|
|
652
|
+
break
|
|
653
|
+
k += 1
|
|
654
|
+
return False
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
@register(
|
|
658
|
+
name="Carol Prime",
|
|
659
|
+
category="primes",
|
|
660
|
+
oeis="A091516",
|
|
661
|
+
description=(
|
|
662
|
+
"A prime of the form (2^n − 1)^2 − 2 for some positive integer n."
|
|
663
|
+
),
|
|
664
|
+
aliases=["carol_prime"],
|
|
665
|
+
)
|
|
666
|
+
def is_carol_prime(n: int) -> bool:
|
|
667
|
+
"""Return ``True`` if *n* is a Carol prime.
|
|
668
|
+
|
|
669
|
+
A Carol prime has the form ``(2^k − 1)^2 − 2`` for some positive integer
|
|
670
|
+
*k*. The sequence begins: 7, 47, 223, 3967, 16127, …
|
|
671
|
+
|
|
672
|
+
Parameters
|
|
673
|
+
----------
|
|
674
|
+
n:
|
|
675
|
+
Integer to test.
|
|
676
|
+
|
|
677
|
+
Returns
|
|
678
|
+
-------
|
|
679
|
+
bool
|
|
680
|
+
|
|
681
|
+
Example
|
|
682
|
+
-------
|
|
683
|
+
>>> is_carol_prime(7) # (2^2 - 1)^2 - 2 = 7
|
|
684
|
+
True
|
|
685
|
+
>>> is_carol_prime(47) # (2^3 - 1)^2 - 2 = 47
|
|
686
|
+
True
|
|
687
|
+
>>> is_carol_prime(11)
|
|
688
|
+
False
|
|
689
|
+
|
|
690
|
+
Edge cases
|
|
691
|
+
----------
|
|
692
|
+
* ``n <= 1`` returns ``False``.
|
|
693
|
+
"""
|
|
694
|
+
if n <= 1:
|
|
695
|
+
return False
|
|
696
|
+
if not is_prime(n):
|
|
697
|
+
return False
|
|
698
|
+
k = 1
|
|
699
|
+
while True:
|
|
700
|
+
carol = (2 ** k - 1) ** 2 - 2
|
|
701
|
+
if carol == n:
|
|
702
|
+
return True
|
|
703
|
+
if carol > n:
|
|
704
|
+
break
|
|
705
|
+
k += 1
|
|
706
|
+
return False
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
@register(
|
|
710
|
+
name="Kynea Prime",
|
|
711
|
+
category="primes",
|
|
712
|
+
oeis="A091515",
|
|
713
|
+
description=(
|
|
714
|
+
"A prime of the form (2^n + 1)^2 − 2 for some positive integer n."
|
|
715
|
+
),
|
|
716
|
+
aliases=["kynea_prime"],
|
|
717
|
+
)
|
|
718
|
+
def is_kynea_prime(n: int) -> bool:
|
|
719
|
+
"""Return ``True`` if *n* is a Kynea prime.
|
|
720
|
+
|
|
721
|
+
A Kynea prime has the form ``(2^k + 1)^2 − 2`` for some positive integer
|
|
722
|
+
*k*. The sequence begins: 7, 23, 79, 1087, 66047, …
|
|
723
|
+
|
|
724
|
+
Parameters
|
|
725
|
+
----------
|
|
726
|
+
n:
|
|
727
|
+
Integer to test.
|
|
728
|
+
|
|
729
|
+
Returns
|
|
730
|
+
-------
|
|
731
|
+
bool
|
|
732
|
+
|
|
733
|
+
Example
|
|
734
|
+
-------
|
|
735
|
+
>>> is_kynea_prime(7) # (2^1 + 1)^2 - 2 = 7
|
|
736
|
+
True
|
|
737
|
+
>>> is_kynea_prime(23) # (2^2 + 1)^2 - 2 = 23
|
|
738
|
+
True
|
|
739
|
+
>>> is_kynea_prime(11)
|
|
740
|
+
False
|
|
741
|
+
|
|
742
|
+
Edge cases
|
|
743
|
+
----------
|
|
744
|
+
* ``n <= 1`` returns ``False``.
|
|
745
|
+
"""
|
|
746
|
+
if n <= 1:
|
|
747
|
+
return False
|
|
748
|
+
if not is_prime(n):
|
|
749
|
+
return False
|
|
750
|
+
k = 1
|
|
751
|
+
while True:
|
|
752
|
+
kynea = (2 ** k + 1) ** 2 - 2
|
|
753
|
+
if kynea == n:
|
|
754
|
+
return True
|
|
755
|
+
if kynea > n:
|
|
756
|
+
break
|
|
757
|
+
k += 1
|
|
758
|
+
return False
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
# Pre-compute Leyland numbers up to a reasonable bound for membership tests.
|
|
762
|
+
def _build_leyland_set(max_base: int = 20) -> frozenset:
|
|
763
|
+
"""Return the set of Leyland numbers x^y + y^x for 2 <= y <= x <= max_base."""
|
|
764
|
+
s: set = set()
|
|
765
|
+
for x in range(2, max_base + 1):
|
|
766
|
+
for y in range(2, x + 1):
|
|
767
|
+
s.add(x ** y + y ** x)
|
|
768
|
+
return frozenset(s)
|
|
769
|
+
|
|
770
|
+
_LEYLAND_NUMBERS: frozenset = _build_leyland_set(20)
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
@register(
|
|
774
|
+
name="Leyland Prime",
|
|
775
|
+
category="primes",
|
|
776
|
+
oeis="A094133",
|
|
777
|
+
description=(
|
|
778
|
+
"A prime of the form x^y + y^x for integers x, y > 1."
|
|
779
|
+
),
|
|
780
|
+
aliases=["leyland_prime"],
|
|
781
|
+
)
|
|
782
|
+
def is_leyland_prime(n: int) -> bool:
|
|
783
|
+
"""Return ``True`` if *n* is a Leyland prime.
|
|
784
|
+
|
|
785
|
+
A Leyland prime is a prime that can be written as ``x^y + y^x`` for some
|
|
786
|
+
integers ``x > y > 1``. This implementation checks bases up to 20 × 20,
|
|
787
|
+
covering Leyland primes including 17, 593, 32993, …
|
|
788
|
+
|
|
789
|
+
Parameters
|
|
790
|
+
----------
|
|
791
|
+
n:
|
|
792
|
+
Integer to test.
|
|
793
|
+
|
|
794
|
+
Returns
|
|
795
|
+
-------
|
|
796
|
+
bool
|
|
797
|
+
|
|
798
|
+
Example
|
|
799
|
+
-------
|
|
800
|
+
>>> is_leyland_prime(17) # 2^3 + 3^2 = 8 + 9 = 17
|
|
801
|
+
True
|
|
802
|
+
>>> is_leyland_prime(593) # 2^7 + 7^2 = 128 + 49... wait, that's 177
|
|
803
|
+
False
|
|
804
|
+
>>> is_leyland_prime(32993) # 2^15 + 15^2 ... verified Leyland prime
|
|
805
|
+
True
|
|
806
|
+
|
|
807
|
+
Notes
|
|
808
|
+
-----
|
|
809
|
+
Only Leyland numbers generated with bases up to 20 are checked. Very large
|
|
810
|
+
Leyland primes requiring bases > 20 will return ``False``.
|
|
811
|
+
|
|
812
|
+
Edge cases
|
|
813
|
+
----------
|
|
814
|
+
* ``n <= 1`` returns ``False``.
|
|
815
|
+
"""
|
|
816
|
+
if n <= 1:
|
|
817
|
+
return False
|
|
818
|
+
if not is_prime(n):
|
|
819
|
+
return False
|
|
820
|
+
return n in _LEYLAND_NUMBERS
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
@register(
|
|
824
|
+
name="Pierpont Prime",
|
|
825
|
+
category="primes",
|
|
826
|
+
oeis="A005109",
|
|
827
|
+
description=(
|
|
828
|
+
"A prime of the form 2^u · 3^v + 1 for non-negative integers u, v."
|
|
829
|
+
),
|
|
830
|
+
aliases=["pierpont_prime"],
|
|
831
|
+
)
|
|
832
|
+
def is_pierpont_prime(n: int) -> bool:
|
|
833
|
+
"""Return ``True`` if *n* is a Pierpont prime.
|
|
834
|
+
|
|
835
|
+
A Pierpont prime is a prime of the form ``2^u * 3^v + 1`` where *u* and
|
|
836
|
+
*v* are non-negative integers (not both zero when the result must be prime).
|
|
837
|
+
Equivalently, ``n − 1`` must be 3-smooth (all prime factors are 2 or 3).
|
|
838
|
+
|
|
839
|
+
Parameters
|
|
840
|
+
----------
|
|
841
|
+
n:
|
|
842
|
+
Integer to test.
|
|
843
|
+
|
|
844
|
+
Returns
|
|
845
|
+
-------
|
|
846
|
+
bool
|
|
847
|
+
|
|
848
|
+
Example
|
|
849
|
+
-------
|
|
850
|
+
>>> is_pierpont_prime(2) # 2^1 * 3^0 + 1 = 2... wait, 2^0*3^0+1=2
|
|
851
|
+
True
|
|
852
|
+
>>> is_pierpont_prime(3) # 2^1 + 1 = 3
|
|
853
|
+
True
|
|
854
|
+
>>> is_pierpont_prime(7) # 2^1 * 3^1 + 1 = 7
|
|
855
|
+
True
|
|
856
|
+
>>> is_pierpont_prime(13) # 12 = 4*3 = 2^2*3^1, 12+1=13
|
|
857
|
+
True
|
|
858
|
+
>>> is_pierpont_prime(11) # 10 = 2*5, 5 is not 2 or 3
|
|
859
|
+
False
|
|
860
|
+
|
|
861
|
+
Edge cases
|
|
862
|
+
----------
|
|
863
|
+
* ``n <= 1`` returns ``False``.
|
|
864
|
+
"""
|
|
865
|
+
if n <= 1:
|
|
866
|
+
return False
|
|
867
|
+
if not is_prime(n):
|
|
868
|
+
return False
|
|
869
|
+
m = n - 1
|
|
870
|
+
if m == 0:
|
|
871
|
+
return False
|
|
872
|
+
while m % 2 == 0:
|
|
873
|
+
m //= 2
|
|
874
|
+
while m % 3 == 0:
|
|
875
|
+
m //= 3
|
|
876
|
+
return m == 1
|
|
877
|
+
|
|
878
|
+
|
|
879
|
+
@register(
|
|
880
|
+
name="Wagstaff Prime",
|
|
881
|
+
category="primes",
|
|
882
|
+
oeis="A000978",
|
|
883
|
+
description=(
|
|
884
|
+
"A prime of the form (2^p + 1) / 3 where p is an odd prime."
|
|
885
|
+
),
|
|
886
|
+
aliases=["wagstaff_prime"],
|
|
887
|
+
)
|
|
888
|
+
def is_wagstaff_prime(n: int) -> bool:
|
|
889
|
+
"""Return ``True`` if *n* is a Wagstaff prime.
|
|
890
|
+
|
|
891
|
+
A Wagstaff prime has the form ``(2^p + 1) / 3`` where *p* is an odd prime.
|
|
892
|
+
This implementation checks candidate exponents *p* such that
|
|
893
|
+
``(2^p + 1) / 3 == n``, iterating until the expression exceeds *n*.
|
|
894
|
+
|
|
895
|
+
Parameters
|
|
896
|
+
----------
|
|
897
|
+
n:
|
|
898
|
+
Integer to test.
|
|
899
|
+
|
|
900
|
+
Returns
|
|
901
|
+
-------
|
|
902
|
+
bool
|
|
903
|
+
|
|
904
|
+
Example
|
|
905
|
+
-------
|
|
906
|
+
>>> is_wagstaff_prime(3) # (2^3 + 1) / 3 = 3
|
|
907
|
+
True
|
|
908
|
+
>>> is_wagstaff_prime(11) # (2^5 + 1) / 3 = 11
|
|
909
|
+
True
|
|
910
|
+
>>> is_wagstaff_prime(43) # (2^7 + 1) / 3 = 43
|
|
911
|
+
True
|
|
912
|
+
>>> is_wagstaff_prime(7)
|
|
913
|
+
False
|
|
914
|
+
|
|
915
|
+
Edge cases
|
|
916
|
+
----------
|
|
917
|
+
* ``n <= 1`` returns ``False``.
|
|
918
|
+
"""
|
|
919
|
+
if n <= 1:
|
|
920
|
+
return False
|
|
921
|
+
if not is_prime(n):
|
|
922
|
+
return False
|
|
923
|
+
# Check odd prime exponents p
|
|
924
|
+
p = 3
|
|
925
|
+
while True:
|
|
926
|
+
numerator = (2 ** p) + 1
|
|
927
|
+
if numerator % 3 != 0:
|
|
928
|
+
p = next_prime(p)
|
|
929
|
+
if 2 ** p > 3 * n + 1:
|
|
930
|
+
break
|
|
931
|
+
continue
|
|
932
|
+
candidate = numerator // 3
|
|
933
|
+
if candidate == n:
|
|
934
|
+
return True
|
|
935
|
+
if candidate > n:
|
|
936
|
+
break
|
|
937
|
+
p = next_prime(p)
|
|
938
|
+
return False
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
# ---------------------------------------------------------------------------
|
|
942
|
+
# GROUP 2 — Relationship-based primes
|
|
943
|
+
# ---------------------------------------------------------------------------
|
|
944
|
+
|
|
945
|
+
@register(
|
|
946
|
+
name="Cousin Prime",
|
|
947
|
+
category="primes",
|
|
948
|
+
oeis="A046132",
|
|
949
|
+
description=(
|
|
950
|
+
"A prime p such that p + 4 or p − 4 is also prime."
|
|
951
|
+
),
|
|
952
|
+
aliases=["cousin_prime"],
|
|
953
|
+
)
|
|
954
|
+
def is_cousin_prime(n: int) -> bool:
|
|
955
|
+
"""Return ``True`` if *n* is a cousin prime.
|
|
956
|
+
|
|
957
|
+
A cousin prime is a prime *p* for which *p + 4* or *p − 4* is also prime,
|
|
958
|
+
forming a cousin-prime pair with gap 4.
|
|
959
|
+
|
|
960
|
+
Parameters
|
|
961
|
+
----------
|
|
962
|
+
n:
|
|
963
|
+
Integer to test.
|
|
964
|
+
|
|
965
|
+
Returns
|
|
966
|
+
-------
|
|
967
|
+
bool
|
|
968
|
+
|
|
969
|
+
Example
|
|
970
|
+
-------
|
|
971
|
+
>>> is_cousin_prime(7) # 3 and 7 differ by 4
|
|
972
|
+
True
|
|
973
|
+
>>> is_cousin_prime(13) # 13 and 17 differ by 4
|
|
974
|
+
True
|
|
975
|
+
>>> is_cousin_prime(5) # 1 and 9 — neither is prime
|
|
976
|
+
False
|
|
977
|
+
|
|
978
|
+
Edge cases
|
|
979
|
+
----------
|
|
980
|
+
* ``n <= 1`` returns ``False``.
|
|
981
|
+
"""
|
|
982
|
+
if not is_prime(n):
|
|
983
|
+
return False
|
|
984
|
+
return is_prime(n + 4) or is_prime(n - 4)
|
|
985
|
+
|
|
986
|
+
|
|
987
|
+
@register(
|
|
988
|
+
name="Sexy Prime",
|
|
989
|
+
category="primes",
|
|
990
|
+
oeis="A023201",
|
|
991
|
+
description=(
|
|
992
|
+
"A prime p such that p + 6 or p − 6 is also prime "
|
|
993
|
+
"(primes differing by 6)."
|
|
994
|
+
),
|
|
995
|
+
aliases=["sexy_prime"],
|
|
996
|
+
)
|
|
997
|
+
def is_sexy_prime(n: int) -> bool:
|
|
998
|
+
"""Return ``True`` if *n* is a sexy prime.
|
|
999
|
+
|
|
1000
|
+
A sexy prime is a prime *p* such that *p + 6* or *p − 6* is also prime.
|
|
1001
|
+
The name derives from the Latin *sex* (six).
|
|
1002
|
+
|
|
1003
|
+
Parameters
|
|
1004
|
+
----------
|
|
1005
|
+
n:
|
|
1006
|
+
Integer to test.
|
|
1007
|
+
|
|
1008
|
+
Returns
|
|
1009
|
+
-------
|
|
1010
|
+
bool
|
|
1011
|
+
|
|
1012
|
+
Example
|
|
1013
|
+
-------
|
|
1014
|
+
>>> is_sexy_prime(5) # 5 and 11 differ by 6
|
|
1015
|
+
True
|
|
1016
|
+
>>> is_sexy_prime(7) # 7 and 13 differ by 6
|
|
1017
|
+
True
|
|
1018
|
+
>>> is_sexy_prime(23) # 17 and 23 differ by 6
|
|
1019
|
+
True
|
|
1020
|
+
>>> is_sexy_prime(3) # 3-6=-3 not prime, 3+6=9=3² not prime
|
|
1021
|
+
False
|
|
1022
|
+
|
|
1023
|
+
Edge cases
|
|
1024
|
+
----------
|
|
1025
|
+
* ``n <= 1`` returns ``False``.
|
|
1026
|
+
"""
|
|
1027
|
+
if not is_prime(n):
|
|
1028
|
+
return False
|
|
1029
|
+
return is_prime(n + 6) or is_prime(n - 6)
|
|
1030
|
+
|
|
1031
|
+
|
|
1032
|
+
@register(
|
|
1033
|
+
name="Prime Triplet",
|
|
1034
|
+
category="primes",
|
|
1035
|
+
oeis="A022004",
|
|
1036
|
+
description=(
|
|
1037
|
+
"A prime p that is part of a prime triplet of the form "
|
|
1038
|
+
"(p, p+2, p+6) or (p, p+4, p+6)."
|
|
1039
|
+
),
|
|
1040
|
+
aliases=["prime_triplet"],
|
|
1041
|
+
)
|
|
1042
|
+
def is_prime_triplet(n: int) -> bool:
|
|
1043
|
+
"""Return ``True`` if *n* belongs to a prime triplet.
|
|
1044
|
+
|
|
1045
|
+
A prime triplet is a set of three primes of the form ``(p, p+2, p+6)`` or
|
|
1046
|
+
``(p, p+4, p+6)``. The number *n* qualifies if it can serve as the
|
|
1047
|
+
smallest element *p* of either form.
|
|
1048
|
+
|
|
1049
|
+
Parameters
|
|
1050
|
+
----------
|
|
1051
|
+
n:
|
|
1052
|
+
Integer to test.
|
|
1053
|
+
|
|
1054
|
+
Returns
|
|
1055
|
+
-------
|
|
1056
|
+
bool
|
|
1057
|
+
|
|
1058
|
+
Example
|
|
1059
|
+
-------
|
|
1060
|
+
>>> is_prime_triplet(5) # (5, 7, 11) — form (p, p+2, p+6)
|
|
1061
|
+
True
|
|
1062
|
+
>>> is_prime_triplet(7) # (7, 11, 13) — form (p, p+4, p+6)
|
|
1063
|
+
True
|
|
1064
|
+
>>> is_prime_triplet(11) # (11, 13, 17) — (p, p+2, p+6)
|
|
1065
|
+
True
|
|
1066
|
+
>>> is_prime_triplet(23)
|
|
1067
|
+
False
|
|
1068
|
+
|
|
1069
|
+
Edge cases
|
|
1070
|
+
----------
|
|
1071
|
+
* ``n <= 1`` returns ``False``.
|
|
1072
|
+
"""
|
|
1073
|
+
if not is_prime(n):
|
|
1074
|
+
return False
|
|
1075
|
+
form1 = is_prime(n + 2) and is_prime(n + 6)
|
|
1076
|
+
form2 = is_prime(n + 4) and is_prime(n + 6)
|
|
1077
|
+
return form1 or form2
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
@register(
|
|
1081
|
+
name="Balanced Prime",
|
|
1082
|
+
category="primes",
|
|
1083
|
+
oeis="A006562",
|
|
1084
|
+
description=(
|
|
1085
|
+
"A prime that equals the arithmetic mean of its neighbouring primes "
|
|
1086
|
+
"(the prime immediately below and immediately above it)."
|
|
1087
|
+
),
|
|
1088
|
+
aliases=["balanced_prime"],
|
|
1089
|
+
)
|
|
1090
|
+
def is_balanced_prime(n: int) -> bool:
|
|
1091
|
+
"""Return ``True`` if *n* is a balanced prime.
|
|
1092
|
+
|
|
1093
|
+
A balanced prime is a prime *p* such that ``p == (prev_prime(p) + next_prime(p)) / 2``,
|
|
1094
|
+
i.e. it is the arithmetic mean of its immediate prime neighbours.
|
|
1095
|
+
|
|
1096
|
+
Parameters
|
|
1097
|
+
----------
|
|
1098
|
+
n:
|
|
1099
|
+
Integer to test.
|
|
1100
|
+
|
|
1101
|
+
Returns
|
|
1102
|
+
-------
|
|
1103
|
+
bool
|
|
1104
|
+
|
|
1105
|
+
Example
|
|
1106
|
+
-------
|
|
1107
|
+
>>> is_balanced_prime(5) # prev=3, next=7; (3+7)/2=5
|
|
1108
|
+
True
|
|
1109
|
+
>>> is_balanced_prime(53) # prev=47, next=59; (47+59)/2=53
|
|
1110
|
+
True
|
|
1111
|
+
>>> is_balanced_prime(7) # prev=5, next=11; (5+11)/2=8 ≠ 7
|
|
1112
|
+
False
|
|
1113
|
+
|
|
1114
|
+
Edge cases
|
|
1115
|
+
----------
|
|
1116
|
+
* ``n <= 2`` returns ``False`` (2 has no previous prime).
|
|
1117
|
+
"""
|
|
1118
|
+
if n <= 2:
|
|
1119
|
+
return False
|
|
1120
|
+
if not is_prime(n):
|
|
1121
|
+
return False
|
|
1122
|
+
pp = prev_prime(n)
|
|
1123
|
+
np_ = next_prime(n)
|
|
1124
|
+
return (pp + np_) == 2 * n
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
@register(
|
|
1128
|
+
name="Isolated Prime",
|
|
1129
|
+
category="primes",
|
|
1130
|
+
oeis="A007510",
|
|
1131
|
+
description=(
|
|
1132
|
+
"A prime p such that neither p − 2 nor p + 2 is prime "
|
|
1133
|
+
"(not part of any twin-prime pair)."
|
|
1134
|
+
),
|
|
1135
|
+
aliases=["isolated_prime"],
|
|
1136
|
+
)
|
|
1137
|
+
def is_isolated_prime(n: int) -> bool:
|
|
1138
|
+
"""Return ``True`` if *n* is an isolated prime.
|
|
1139
|
+
|
|
1140
|
+
An isolated prime is a prime *p* for which both ``p − 2`` and ``p + 2``
|
|
1141
|
+
are composite. In other words, it is not a member of any twin-prime pair.
|
|
1142
|
+
|
|
1143
|
+
Parameters
|
|
1144
|
+
----------
|
|
1145
|
+
n:
|
|
1146
|
+
Integer to test.
|
|
1147
|
+
|
|
1148
|
+
Returns
|
|
1149
|
+
-------
|
|
1150
|
+
bool
|
|
1151
|
+
|
|
1152
|
+
Example
|
|
1153
|
+
-------
|
|
1154
|
+
>>> is_isolated_prime(23) # 21=3*7, 25=5² — both composite
|
|
1155
|
+
True
|
|
1156
|
+
>>> is_isolated_prime(5) # 3 is prime (twin with 5)
|
|
1157
|
+
False
|
|
1158
|
+
|
|
1159
|
+
Edge cases
|
|
1160
|
+
----------
|
|
1161
|
+
* ``n <= 1`` returns ``False``.
|
|
1162
|
+
"""
|
|
1163
|
+
if not is_prime(n):
|
|
1164
|
+
return False
|
|
1165
|
+
return not is_prime(n - 2) and not is_prime(n + 2)
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
@register(
|
|
1169
|
+
name="Chen Prime",
|
|
1170
|
+
category="primes",
|
|
1171
|
+
oeis="A109611",
|
|
1172
|
+
description=(
|
|
1173
|
+
"A prime p such that p + 2 is either prime or semiprime "
|
|
1174
|
+
"(product of exactly two primes)."
|
|
1175
|
+
),
|
|
1176
|
+
aliases=["chen_prime"],
|
|
1177
|
+
)
|
|
1178
|
+
def is_chen_prime(n: int) -> bool:
|
|
1179
|
+
"""Return ``True`` if *n* is a Chen prime.
|
|
1180
|
+
|
|
1181
|
+
A Chen prime is a prime *p* such that ``p + 2`` is either prime or
|
|
1182
|
+
semiprime (i.e. has exactly two prime factors counting multiplicity).
|
|
1183
|
+
|
|
1184
|
+
Parameters
|
|
1185
|
+
----------
|
|
1186
|
+
n:
|
|
1187
|
+
Integer to test.
|
|
1188
|
+
|
|
1189
|
+
Returns
|
|
1190
|
+
-------
|
|
1191
|
+
bool
|
|
1192
|
+
|
|
1193
|
+
Example
|
|
1194
|
+
-------
|
|
1195
|
+
>>> is_chen_prime(2) # 2+2=4=2², semiprime
|
|
1196
|
+
True
|
|
1197
|
+
>>> is_chen_prime(3) # 3+2=5, prime
|
|
1198
|
+
True
|
|
1199
|
+
>>> is_chen_prime(5) # 5+2=7, prime
|
|
1200
|
+
True
|
|
1201
|
+
>>> is_chen_prime(7) # 7+2=9=3², semiprime
|
|
1202
|
+
True
|
|
1203
|
+
>>> is_chen_prime(11) # 11+2=13, prime
|
|
1204
|
+
True
|
|
1205
|
+
|
|
1206
|
+
Edge cases
|
|
1207
|
+
----------
|
|
1208
|
+
* ``n <= 1`` returns ``False``.
|
|
1209
|
+
"""
|
|
1210
|
+
if not is_prime(n):
|
|
1211
|
+
return False
|
|
1212
|
+
return is_prime(n + 2) or is_semiprime(n + 2)
|
|
1213
|
+
|
|
1214
|
+
|
|
1215
|
+
@register(
|
|
1216
|
+
name="Strong Prime",
|
|
1217
|
+
category="primes",
|
|
1218
|
+
oeis="A051634",
|
|
1219
|
+
description=(
|
|
1220
|
+
"A prime greater than the arithmetic mean of its immediate "
|
|
1221
|
+
"prime neighbours."
|
|
1222
|
+
),
|
|
1223
|
+
aliases=["strong_prime"],
|
|
1224
|
+
)
|
|
1225
|
+
def is_strong_prime(n: int) -> bool:
|
|
1226
|
+
"""Return ``True`` if *n* is a strong prime.
|
|
1227
|
+
|
|
1228
|
+
A strong prime is a prime *p* that is strictly greater than the arithmetic
|
|
1229
|
+
mean of the prime immediately below it and the prime immediately above it.
|
|
1230
|
+
|
|
1231
|
+
Parameters
|
|
1232
|
+
----------
|
|
1233
|
+
n:
|
|
1234
|
+
Integer to test.
|
|
1235
|
+
|
|
1236
|
+
Returns
|
|
1237
|
+
-------
|
|
1238
|
+
bool
|
|
1239
|
+
|
|
1240
|
+
Example
|
|
1241
|
+
-------
|
|
1242
|
+
>>> is_strong_prime(11) # prev=7, next=13; mean=10; 11>10
|
|
1243
|
+
True
|
|
1244
|
+
>>> is_strong_prime(7) # prev=5, next=11; mean=8; 7<8
|
|
1245
|
+
False
|
|
1246
|
+
|
|
1247
|
+
Edge cases
|
|
1248
|
+
----------
|
|
1249
|
+
* ``n <= 2`` returns ``False``.
|
|
1250
|
+
"""
|
|
1251
|
+
if n <= 2:
|
|
1252
|
+
return False
|
|
1253
|
+
if not is_prime(n):
|
|
1254
|
+
return False
|
|
1255
|
+
pp = prev_prime(n)
|
|
1256
|
+
np_ = next_prime(n)
|
|
1257
|
+
return 2 * n > pp + np_
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
@register(
|
|
1261
|
+
name="Weak Prime",
|
|
1262
|
+
category="primes",
|
|
1263
|
+
oeis="A051635",
|
|
1264
|
+
description=(
|
|
1265
|
+
"A prime less than the arithmetic mean of its immediate "
|
|
1266
|
+
"prime neighbours."
|
|
1267
|
+
),
|
|
1268
|
+
aliases=["weak_prime"],
|
|
1269
|
+
)
|
|
1270
|
+
def is_weak_prime(n: int) -> bool:
|
|
1271
|
+
"""Return ``True`` if *n* is a weak prime.
|
|
1272
|
+
|
|
1273
|
+
A weak prime is a prime *p* that is strictly less than the arithmetic mean
|
|
1274
|
+
of the prime immediately below it and the prime immediately above it.
|
|
1275
|
+
|
|
1276
|
+
Parameters
|
|
1277
|
+
----------
|
|
1278
|
+
n:
|
|
1279
|
+
Integer to test.
|
|
1280
|
+
|
|
1281
|
+
Returns
|
|
1282
|
+
-------
|
|
1283
|
+
bool
|
|
1284
|
+
|
|
1285
|
+
Example
|
|
1286
|
+
-------
|
|
1287
|
+
>>> is_weak_prime(3) # prev=2, next=5; mean=3.5; 3<3.5
|
|
1288
|
+
True
|
|
1289
|
+
>>> is_weak_prime(7) # prev=5, next=11; mean=8; 7<8
|
|
1290
|
+
True
|
|
1291
|
+
>>> is_weak_prime(11) # prev=7, next=13; mean=10; 11>10
|
|
1292
|
+
False
|
|
1293
|
+
|
|
1294
|
+
Edge cases
|
|
1295
|
+
----------
|
|
1296
|
+
* ``n <= 2`` returns ``False``.
|
|
1297
|
+
"""
|
|
1298
|
+
if n <= 2:
|
|
1299
|
+
return False
|
|
1300
|
+
if not is_prime(n):
|
|
1301
|
+
return False
|
|
1302
|
+
pp = prev_prime(n)
|
|
1303
|
+
np_ = next_prime(n)
|
|
1304
|
+
return 2 * n < pp + np_
|
|
1305
|
+
|
|
1306
|
+
|
|
1307
|
+
# ---------------------------------------------------------------------------
|
|
1308
|
+
# GROUP 3 — Digital/representational primes
|
|
1309
|
+
# ---------------------------------------------------------------------------
|
|
1310
|
+
|
|
1311
|
+
@register(
|
|
1312
|
+
name="Palindromic Prime",
|
|
1313
|
+
category="primes",
|
|
1314
|
+
oeis="A002385",
|
|
1315
|
+
description=(
|
|
1316
|
+
"A prime whose decimal representation reads the same forwards and "
|
|
1317
|
+
"backwards."
|
|
1318
|
+
),
|
|
1319
|
+
aliases=["palindromic_prime"],
|
|
1320
|
+
)
|
|
1321
|
+
def is_palindromic_prime(n: int) -> bool:
|
|
1322
|
+
"""Return ``True`` if *n* is a palindromic prime.
|
|
1323
|
+
|
|
1324
|
+
A palindromic prime is both prime and a palindrome in base 10
|
|
1325
|
+
(its digits read identically in both directions).
|
|
1326
|
+
|
|
1327
|
+
Parameters
|
|
1328
|
+
----------
|
|
1329
|
+
n:
|
|
1330
|
+
Integer to test.
|
|
1331
|
+
|
|
1332
|
+
Returns
|
|
1333
|
+
-------
|
|
1334
|
+
bool
|
|
1335
|
+
|
|
1336
|
+
Example
|
|
1337
|
+
-------
|
|
1338
|
+
>>> is_palindromic_prime(11)
|
|
1339
|
+
True
|
|
1340
|
+
>>> is_palindromic_prime(131)
|
|
1341
|
+
True
|
|
1342
|
+
>>> is_palindromic_prime(13)
|
|
1343
|
+
False
|
|
1344
|
+
|
|
1345
|
+
Edge cases
|
|
1346
|
+
----------
|
|
1347
|
+
* ``n <= 1`` returns ``False``.
|
|
1348
|
+
* All single-digit primes (2, 3, 5, 7) are palindromic primes.
|
|
1349
|
+
"""
|
|
1350
|
+
if not is_prime(n):
|
|
1351
|
+
return False
|
|
1352
|
+
s = str(n)
|
|
1353
|
+
return s == s[::-1]
|
|
1354
|
+
|
|
1355
|
+
|
|
1356
|
+
@register(
|
|
1357
|
+
name="Emirp",
|
|
1358
|
+
category="primes",
|
|
1359
|
+
oeis="A006567",
|
|
1360
|
+
description=(
|
|
1361
|
+
"A prime whose digit reversal is a different prime."
|
|
1362
|
+
),
|
|
1363
|
+
aliases=["emirp"],
|
|
1364
|
+
)
|
|
1365
|
+
def is_emirp(n: int) -> bool:
|
|
1366
|
+
"""Return ``True`` if *n* is an emirp.
|
|
1367
|
+
|
|
1368
|
+
An emirp (prime spelled backwards) is a prime *p* whose digit reversal
|
|
1369
|
+
is a *different* prime. Palindromic primes are excluded since reversing
|
|
1370
|
+
them yields the same number.
|
|
1371
|
+
|
|
1372
|
+
Parameters
|
|
1373
|
+
----------
|
|
1374
|
+
n:
|
|
1375
|
+
Integer to test.
|
|
1376
|
+
|
|
1377
|
+
Returns
|
|
1378
|
+
-------
|
|
1379
|
+
bool
|
|
1380
|
+
|
|
1381
|
+
Example
|
|
1382
|
+
-------
|
|
1383
|
+
>>> is_emirp(13) # reversed: 31, prime, and 31 ≠ 13
|
|
1384
|
+
True
|
|
1385
|
+
>>> is_emirp(11) # palindrome — reversed equals itself
|
|
1386
|
+
False
|
|
1387
|
+
>>> is_emirp(17) # reversed: 71, prime
|
|
1388
|
+
True
|
|
1389
|
+
|
|
1390
|
+
Edge cases
|
|
1391
|
+
----------
|
|
1392
|
+
* ``n <= 1`` returns ``False``.
|
|
1393
|
+
"""
|
|
1394
|
+
if not is_prime(n):
|
|
1395
|
+
return False
|
|
1396
|
+
rev = int(str(n)[::-1])
|
|
1397
|
+
return rev != n and is_prime(rev)
|
|
1398
|
+
|
|
1399
|
+
|
|
1400
|
+
@register(
|
|
1401
|
+
name="Circular Prime",
|
|
1402
|
+
category="primes",
|
|
1403
|
+
oeis="A068652",
|
|
1404
|
+
description=(
|
|
1405
|
+
"A prime all of whose cyclic rotations of digits are also prime."
|
|
1406
|
+
),
|
|
1407
|
+
aliases=["circular_prime"],
|
|
1408
|
+
)
|
|
1409
|
+
def is_circular_prime(n: int) -> bool:
|
|
1410
|
+
"""Return ``True`` if *n* is a circular prime.
|
|
1411
|
+
|
|
1412
|
+
A circular prime is a prime for which every cyclic rotation of its digits
|
|
1413
|
+
is also prime. For example, 197 yields rotations 197, 971, 719 — all prime.
|
|
1414
|
+
|
|
1415
|
+
Parameters
|
|
1416
|
+
----------
|
|
1417
|
+
n:
|
|
1418
|
+
Integer to test.
|
|
1419
|
+
|
|
1420
|
+
Returns
|
|
1421
|
+
-------
|
|
1422
|
+
bool
|
|
1423
|
+
|
|
1424
|
+
Example
|
|
1425
|
+
-------
|
|
1426
|
+
>>> is_circular_prime(197)
|
|
1427
|
+
True
|
|
1428
|
+
>>> is_circular_prime(113) # rotation 311 prime, 131 prime, 113 prime
|
|
1429
|
+
True
|
|
1430
|
+
>>> is_circular_prime(19) # 19 prime, 91=7*13 not prime
|
|
1431
|
+
False
|
|
1432
|
+
|
|
1433
|
+
Edge cases
|
|
1434
|
+
----------
|
|
1435
|
+
* ``n <= 1`` returns ``False``.
|
|
1436
|
+
"""
|
|
1437
|
+
if not is_prime(n):
|
|
1438
|
+
return False
|
|
1439
|
+
s = str(n)
|
|
1440
|
+
k = len(s)
|
|
1441
|
+
for i in range(1, k):
|
|
1442
|
+
rotation = int(s[i:] + s[:i])
|
|
1443
|
+
if not is_prime(rotation):
|
|
1444
|
+
return False
|
|
1445
|
+
return True
|
|
1446
|
+
|
|
1447
|
+
|
|
1448
|
+
@register(
|
|
1449
|
+
name="Left-Truncatable Prime",
|
|
1450
|
+
category="primes",
|
|
1451
|
+
oeis="A024785",
|
|
1452
|
+
description=(
|
|
1453
|
+
"A prime that remains prime after repeatedly removing the "
|
|
1454
|
+
"leftmost digit."
|
|
1455
|
+
),
|
|
1456
|
+
aliases=["truncatable_prime_left"],
|
|
1457
|
+
)
|
|
1458
|
+
def is_truncatable_prime_left(n: int) -> bool:
|
|
1459
|
+
"""Return ``True`` if *n* is a left-truncatable prime.
|
|
1460
|
+
|
|
1461
|
+
A left-truncatable prime is a prime such that removing digits from the
|
|
1462
|
+
left one at a time always yields a prime. Single-digit primes are
|
|
1463
|
+
considered trivially left-truncatable.
|
|
1464
|
+
|
|
1465
|
+
Parameters
|
|
1466
|
+
----------
|
|
1467
|
+
n:
|
|
1468
|
+
Integer to test.
|
|
1469
|
+
|
|
1470
|
+
Returns
|
|
1471
|
+
-------
|
|
1472
|
+
bool
|
|
1473
|
+
|
|
1474
|
+
Example
|
|
1475
|
+
-------
|
|
1476
|
+
>>> is_truncatable_prime_left(9137) # 9137→137→37→7, all prime
|
|
1477
|
+
True
|
|
1478
|
+
>>> is_truncatable_prime_left(317) # 317→17→7, all prime
|
|
1479
|
+
True
|
|
1480
|
+
>>> is_truncatable_prime_left(23) # 23→3 prime; 23 prime; ok
|
|
1481
|
+
True
|
|
1482
|
+
|
|
1483
|
+
Edge cases
|
|
1484
|
+
----------
|
|
1485
|
+
* ``n <= 1`` returns ``False``.
|
|
1486
|
+
* Digits of value 0 intermediate results are considered non-prime, so
|
|
1487
|
+
any truncation producing a leading-zero number (< the digit count
|
|
1488
|
+
suggests) is handled by normal integer conversion.
|
|
1489
|
+
"""
|
|
1490
|
+
if not is_prime(n):
|
|
1491
|
+
return False
|
|
1492
|
+
s = str(n)
|
|
1493
|
+
for i in range(1, len(s)):
|
|
1494
|
+
truncated = int(s[i:])
|
|
1495
|
+
if not is_prime(truncated):
|
|
1496
|
+
return False
|
|
1497
|
+
return True
|
|
1498
|
+
|
|
1499
|
+
|
|
1500
|
+
@register(
|
|
1501
|
+
name="Right-Truncatable Prime",
|
|
1502
|
+
category="primes",
|
|
1503
|
+
oeis="A024770",
|
|
1504
|
+
description=(
|
|
1505
|
+
"A prime that remains prime after repeatedly removing the "
|
|
1506
|
+
"rightmost digit."
|
|
1507
|
+
),
|
|
1508
|
+
aliases=["truncatable_prime_right"],
|
|
1509
|
+
)
|
|
1510
|
+
def is_truncatable_prime_right(n: int) -> bool:
|
|
1511
|
+
"""Return ``True`` if *n* is a right-truncatable prime.
|
|
1512
|
+
|
|
1513
|
+
A right-truncatable prime is a prime such that removing digits from the
|
|
1514
|
+
right one at a time always yields a prime. Single-digit primes are
|
|
1515
|
+
trivially right-truncatable.
|
|
1516
|
+
|
|
1517
|
+
Parameters
|
|
1518
|
+
----------
|
|
1519
|
+
n:
|
|
1520
|
+
Integer to test.
|
|
1521
|
+
|
|
1522
|
+
Returns
|
|
1523
|
+
-------
|
|
1524
|
+
bool
|
|
1525
|
+
|
|
1526
|
+
Example
|
|
1527
|
+
-------
|
|
1528
|
+
>>> is_truncatable_prime_right(7393) # 7393→739→73→7, all prime
|
|
1529
|
+
True
|
|
1530
|
+
>>> is_truncatable_prime_right(373) # 373→37→3, all prime
|
|
1531
|
+
True
|
|
1532
|
+
>>> is_truncatable_prime_right(23) # 23→2, both prime
|
|
1533
|
+
True
|
|
1534
|
+
|
|
1535
|
+
Edge cases
|
|
1536
|
+
----------
|
|
1537
|
+
* ``n <= 1`` returns ``False``.
|
|
1538
|
+
"""
|
|
1539
|
+
if not is_prime(n):
|
|
1540
|
+
return False
|
|
1541
|
+
m = n // 10
|
|
1542
|
+
while m > 0:
|
|
1543
|
+
if not is_prime(m):
|
|
1544
|
+
return False
|
|
1545
|
+
m //= 10
|
|
1546
|
+
return True
|
|
1547
|
+
|
|
1548
|
+
|
|
1549
|
+
@register(
|
|
1550
|
+
name="Permutable Prime",
|
|
1551
|
+
category="primes",
|
|
1552
|
+
oeis="A003459",
|
|
1553
|
+
description=(
|
|
1554
|
+
"A prime for which every permutation of its digits is also prime."
|
|
1555
|
+
),
|
|
1556
|
+
aliases=["permutable_prime"],
|
|
1557
|
+
)
|
|
1558
|
+
def is_permutable_prime(n: int) -> bool:
|
|
1559
|
+
"""Return ``True`` if *n* is a permutable prime (absolute prime).
|
|
1560
|
+
|
|
1561
|
+
A permutable prime, also called an absolute prime, is a prime for which
|
|
1562
|
+
every possible permutation of its digits is also prime.
|
|
1563
|
+
|
|
1564
|
+
Parameters
|
|
1565
|
+
----------
|
|
1566
|
+
n:
|
|
1567
|
+
Integer to test.
|
|
1568
|
+
|
|
1569
|
+
Returns
|
|
1570
|
+
-------
|
|
1571
|
+
bool
|
|
1572
|
+
|
|
1573
|
+
Example
|
|
1574
|
+
-------
|
|
1575
|
+
>>> is_permutable_prime(13) # permutations: 13, 31 — both prime
|
|
1576
|
+
True
|
|
1577
|
+
>>> is_permutable_prime(337) # 337, 373, 733 — all prime
|
|
1578
|
+
True
|
|
1579
|
+
>>> is_permutable_prime(7) # single digit
|
|
1580
|
+
True
|
|
1581
|
+
|
|
1582
|
+
Notes
|
|
1583
|
+
-----
|
|
1584
|
+
This check is exponentially expensive in the number of digits. A guard
|
|
1585
|
+
is applied for ``n >= 1_000_000`` to avoid excessive computation.
|
|
1586
|
+
|
|
1587
|
+
Edge cases
|
|
1588
|
+
----------
|
|
1589
|
+
* ``n <= 1`` returns ``False``.
|
|
1590
|
+
* ``n >= 1_000_000`` returns ``False`` (guard limit).
|
|
1591
|
+
"""
|
|
1592
|
+
if not is_prime(n):
|
|
1593
|
+
return False
|
|
1594
|
+
if n >= 1_000_000:
|
|
1595
|
+
return False
|
|
1596
|
+
digits = str(n)
|
|
1597
|
+
for perm in set(itertools.permutations(digits)):
|
|
1598
|
+
candidate = int("".join(perm))
|
|
1599
|
+
if not is_prime(candidate):
|
|
1600
|
+
return False
|
|
1601
|
+
return True
|
|
1602
|
+
|
|
1603
|
+
|
|
1604
|
+
@register(
|
|
1605
|
+
name="Repunit Prime",
|
|
1606
|
+
category="primes",
|
|
1607
|
+
oeis="A004022",
|
|
1608
|
+
description=(
|
|
1609
|
+
"A prime consisting entirely of the digit 1 in decimal "
|
|
1610
|
+
"(a repunit that is prime)."
|
|
1611
|
+
),
|
|
1612
|
+
aliases=["repunit_prime"],
|
|
1613
|
+
)
|
|
1614
|
+
def is_repunit_prime(n: int) -> bool:
|
|
1615
|
+
"""Return ``True`` if *n* is a repunit prime.
|
|
1616
|
+
|
|
1617
|
+
A repunit prime is a prime number whose decimal representation consists
|
|
1618
|
+
solely of the digit 1 (i.e. 11, 1111111111111111111, …). The repunit
|
|
1619
|
+
R_k = (10^k − 1) / 9.
|
|
1620
|
+
|
|
1621
|
+
Parameters
|
|
1622
|
+
----------
|
|
1623
|
+
n:
|
|
1624
|
+
Integer to test.
|
|
1625
|
+
|
|
1626
|
+
Returns
|
|
1627
|
+
-------
|
|
1628
|
+
bool
|
|
1629
|
+
|
|
1630
|
+
Example
|
|
1631
|
+
-------
|
|
1632
|
+
>>> is_repunit_prime(11)
|
|
1633
|
+
True
|
|
1634
|
+
>>> is_repunit_prime(1111111111111111111) # R_19, known repunit prime
|
|
1635
|
+
True
|
|
1636
|
+
>>> is_repunit_prime(111) # 111 = 3 * 37, composite
|
|
1637
|
+
False
|
|
1638
|
+
|
|
1639
|
+
Edge cases
|
|
1640
|
+
----------
|
|
1641
|
+
* Single-digit 1 is not prime, returns ``False``.
|
|
1642
|
+
"""
|
|
1643
|
+
if not is_prime(n):
|
|
1644
|
+
return False
|
|
1645
|
+
return all(c == "1" for c in str(n))
|
|
1646
|
+
|
|
1647
|
+
|
|
1648
|
+
# ---------------------------------------------------------------------------
|
|
1649
|
+
# GROUP 4 — Modular/congruence primes
|
|
1650
|
+
# ---------------------------------------------------------------------------
|
|
1651
|
+
|
|
1652
|
+
@register(
|
|
1653
|
+
name="Pythagorean Prime",
|
|
1654
|
+
category="primes",
|
|
1655
|
+
oeis="A002144",
|
|
1656
|
+
description=(
|
|
1657
|
+
"A prime of the form 4n + 1; equivalently, a prime expressible "
|
|
1658
|
+
"as the sum of two squares."
|
|
1659
|
+
),
|
|
1660
|
+
aliases=["pythagorean_prime"],
|
|
1661
|
+
)
|
|
1662
|
+
def is_pythagorean_prime(n: int) -> bool:
|
|
1663
|
+
"""Return ``True`` if *n* is a Pythagorean prime.
|
|
1664
|
+
|
|
1665
|
+
A Pythagorean prime is a prime congruent to 1 modulo 4, i.e. of the form
|
|
1666
|
+
``4k + 1``. By Fermat's theorem on sums of two squares, these are exactly
|
|
1667
|
+
the odd primes expressible as a sum of two squares.
|
|
1668
|
+
|
|
1669
|
+
Parameters
|
|
1670
|
+
----------
|
|
1671
|
+
n:
|
|
1672
|
+
Integer to test.
|
|
1673
|
+
|
|
1674
|
+
Returns
|
|
1675
|
+
-------
|
|
1676
|
+
bool
|
|
1677
|
+
|
|
1678
|
+
Example
|
|
1679
|
+
-------
|
|
1680
|
+
>>> is_pythagorean_prime(5) # 5 = 4*1 + 1
|
|
1681
|
+
True
|
|
1682
|
+
>>> is_pythagorean_prime(13) # 13 = 4*3 + 1
|
|
1683
|
+
True
|
|
1684
|
+
>>> is_pythagorean_prime(7) # 7 ≡ 3 (mod 4)
|
|
1685
|
+
False
|
|
1686
|
+
|
|
1687
|
+
Edge cases
|
|
1688
|
+
----------
|
|
1689
|
+
* ``n <= 1`` returns ``False``.
|
|
1690
|
+
"""
|
|
1691
|
+
return is_prime(n) and n % 4 == 1
|
|
1692
|
+
|
|
1693
|
+
|
|
1694
|
+
@register(
|
|
1695
|
+
name="Gaussian Prime",
|
|
1696
|
+
category="primes",
|
|
1697
|
+
oeis="A002145",
|
|
1698
|
+
description=(
|
|
1699
|
+
"A real prime that remains prime in the Gaussian integers: "
|
|
1700
|
+
"p = 2, or p ≡ 3 (mod 4)."
|
|
1701
|
+
),
|
|
1702
|
+
aliases=["gaussian_prime"],
|
|
1703
|
+
)
|
|
1704
|
+
def is_gaussian_prime(n: int) -> bool:
|
|
1705
|
+
"""Return ``True`` if *n* is a real Gaussian prime.
|
|
1706
|
+
|
|
1707
|
+
A positive integer *p* is a Gaussian prime (on the real axis of the
|
|
1708
|
+
Gaussian integers ℤ[i]) if and only if it is prime and congruent to
|
|
1709
|
+
3 modulo 4, or equals 2. Primes congruent to 1 mod 4 split in ℤ[i]
|
|
1710
|
+
and are therefore not Gaussian primes on the real axis.
|
|
1711
|
+
|
|
1712
|
+
Parameters
|
|
1713
|
+
----------
|
|
1714
|
+
n:
|
|
1715
|
+
Integer to test.
|
|
1716
|
+
|
|
1717
|
+
Returns
|
|
1718
|
+
-------
|
|
1719
|
+
bool
|
|
1720
|
+
|
|
1721
|
+
Example
|
|
1722
|
+
-------
|
|
1723
|
+
>>> is_gaussian_prime(2)
|
|
1724
|
+
True
|
|
1725
|
+
>>> is_gaussian_prime(3) # 3 ≡ 3 (mod 4)
|
|
1726
|
+
True
|
|
1727
|
+
>>> is_gaussian_prime(7) # 7 ≡ 3 (mod 4)
|
|
1728
|
+
True
|
|
1729
|
+
>>> is_gaussian_prime(5) # 5 ≡ 1 (mod 4), splits as (2+i)(2-i)
|
|
1730
|
+
False
|
|
1731
|
+
|
|
1732
|
+
Edge cases
|
|
1733
|
+
----------
|
|
1734
|
+
* ``n <= 1`` returns ``False``.
|
|
1735
|
+
"""
|
|
1736
|
+
if not is_prime(n):
|
|
1737
|
+
return False
|
|
1738
|
+
return n == 2 or n % 4 == 3
|
|
1739
|
+
|
|
1740
|
+
|
|
1741
|
+
@register(
|
|
1742
|
+
name="Eisenstein Prime",
|
|
1743
|
+
category="primes",
|
|
1744
|
+
oeis="A003627",
|
|
1745
|
+
description=(
|
|
1746
|
+
"A real prime that remains prime in the Eisenstein integers: "
|
|
1747
|
+
"p = 3, or p ≡ 2 (mod 3)."
|
|
1748
|
+
),
|
|
1749
|
+
aliases=["eisenstein_prime"],
|
|
1750
|
+
)
|
|
1751
|
+
def is_eisenstein_prime(n: int) -> bool:
|
|
1752
|
+
"""Return ``True`` if *n* is a real Eisenstein prime.
|
|
1753
|
+
|
|
1754
|
+
A positive integer *p* is an Eisenstein prime (on the real axis of the
|
|
1755
|
+
Eisenstein integers ℤ[ω]) if it is prime and congruent to 2 modulo 3,
|
|
1756
|
+
or equals 3. Primes congruent to 1 mod 3 split in ℤ[ω].
|
|
1757
|
+
|
|
1758
|
+
Parameters
|
|
1759
|
+
----------
|
|
1760
|
+
n:
|
|
1761
|
+
Integer to test.
|
|
1762
|
+
|
|
1763
|
+
Returns
|
|
1764
|
+
-------
|
|
1765
|
+
bool
|
|
1766
|
+
|
|
1767
|
+
Example
|
|
1768
|
+
-------
|
|
1769
|
+
>>> is_eisenstein_prime(2) # 2 ≡ 2 (mod 3)
|
|
1770
|
+
True
|
|
1771
|
+
>>> is_eisenstein_prime(3)
|
|
1772
|
+
True
|
|
1773
|
+
>>> is_eisenstein_prime(5) # 5 ≡ 2 (mod 3)
|
|
1774
|
+
True
|
|
1775
|
+
>>> is_eisenstein_prime(7) # 7 ≡ 1 (mod 3), splits
|
|
1776
|
+
False
|
|
1777
|
+
|
|
1778
|
+
Edge cases
|
|
1779
|
+
----------
|
|
1780
|
+
* ``n <= 1`` returns ``False``.
|
|
1781
|
+
"""
|
|
1782
|
+
if not is_prime(n):
|
|
1783
|
+
return False
|
|
1784
|
+
return n == 3 or n % 3 == 2
|
|
1785
|
+
|
|
1786
|
+
|
|
1787
|
+
@register(
|
|
1788
|
+
name="Wilson Prime",
|
|
1789
|
+
category="primes",
|
|
1790
|
+
oeis="A007540",
|
|
1791
|
+
description=(
|
|
1792
|
+
"A prime p satisfying (p−1)! ≡ −1 (mod p²). "
|
|
1793
|
+
"Only three are known: 5, 13, 563."
|
|
1794
|
+
),
|
|
1795
|
+
aliases=["wilson_prime"],
|
|
1796
|
+
)
|
|
1797
|
+
def is_wilson_prime(n: int) -> bool:
|
|
1798
|
+
"""Return ``True`` if *n* is a Wilson prime.
|
|
1799
|
+
|
|
1800
|
+
A Wilson prime is a prime *p* for which ``(p−1)! ≡ −1 (mod p²)``.
|
|
1801
|
+
Only three Wilson primes are currently known: 5, 13, and 563.
|
|
1802
|
+
|
|
1803
|
+
This implementation computes ``(n−1)! mod n²`` directly using
|
|
1804
|
+
``math.factorial``. To avoid impractically large computation, values
|
|
1805
|
+
of *n* above 600 return ``False`` early (563 is the largest known Wilson
|
|
1806
|
+
prime, and computation for larger primes is infeasible with factorial).
|
|
1807
|
+
|
|
1808
|
+
Parameters
|
|
1809
|
+
----------
|
|
1810
|
+
n:
|
|
1811
|
+
Integer to test.
|
|
1812
|
+
|
|
1813
|
+
Returns
|
|
1814
|
+
-------
|
|
1815
|
+
bool
|
|
1816
|
+
|
|
1817
|
+
Example
|
|
1818
|
+
-------
|
|
1819
|
+
>>> is_wilson_prime(5)
|
|
1820
|
+
True
|
|
1821
|
+
>>> is_wilson_prime(13)
|
|
1822
|
+
True
|
|
1823
|
+
>>> is_wilson_prime(563)
|
|
1824
|
+
True
|
|
1825
|
+
>>> is_wilson_prime(7)
|
|
1826
|
+
False
|
|
1827
|
+
|
|
1828
|
+
Edge cases
|
|
1829
|
+
----------
|
|
1830
|
+
* ``n <= 1`` returns ``False``.
|
|
1831
|
+
* ``n > 600`` returns ``False`` (computation guard).
|
|
1832
|
+
"""
|
|
1833
|
+
if not is_prime(n):
|
|
1834
|
+
return False
|
|
1835
|
+
if n > 600:
|
|
1836
|
+
return False
|
|
1837
|
+
p2 = n * n
|
|
1838
|
+
return math.factorial(n - 1) % p2 == p2 - 1
|
|
1839
|
+
|
|
1840
|
+
|
|
1841
|
+
@register(
|
|
1842
|
+
name="Wieferich Prime",
|
|
1843
|
+
category="primes",
|
|
1844
|
+
oeis="A001220",
|
|
1845
|
+
description=(
|
|
1846
|
+
"A prime p where 2^(p−1) ≡ 1 (mod p²). "
|
|
1847
|
+
"Only two are known: 1093, 3511."
|
|
1848
|
+
),
|
|
1849
|
+
aliases=["wieferich_prime"],
|
|
1850
|
+
)
|
|
1851
|
+
def is_wieferich_prime(n: int) -> bool:
|
|
1852
|
+
"""Return ``True`` if *n* is a Wieferich prime.
|
|
1853
|
+
|
|
1854
|
+
A Wieferich prime is a prime *p* satisfying ``2^(p−1) ≡ 1 (mod p²)``.
|
|
1855
|
+
Only two Wieferich primes are known: 1093 and 3511.
|
|
1856
|
+
|
|
1857
|
+
Although ``pow(2, p-1, p**2)`` can be computed efficiently for large *p*
|
|
1858
|
+
via Python's built-in modular exponentiation, this function checks against
|
|
1859
|
+
the known set ``{1093, 3511}`` because no other Wieferich primes exist
|
|
1860
|
+
below 6.7 × 10¹⁵ (as of 2023), making a computation-only approach
|
|
1861
|
+
practically equivalent.
|
|
1862
|
+
|
|
1863
|
+
Parameters
|
|
1864
|
+
----------
|
|
1865
|
+
n:
|
|
1866
|
+
Integer to test.
|
|
1867
|
+
|
|
1868
|
+
Returns
|
|
1869
|
+
-------
|
|
1870
|
+
bool
|
|
1871
|
+
|
|
1872
|
+
Example
|
|
1873
|
+
-------
|
|
1874
|
+
>>> is_wieferich_prime(1093)
|
|
1875
|
+
True
|
|
1876
|
+
>>> is_wieferich_prime(3511)
|
|
1877
|
+
True
|
|
1878
|
+
>>> is_wieferich_prime(2)
|
|
1879
|
+
False
|
|
1880
|
+
|
|
1881
|
+
Notes
|
|
1882
|
+
-----
|
|
1883
|
+
To verify by computation: ``pow(2, n - 1, n * n) == 1``.
|
|
1884
|
+
"""
|
|
1885
|
+
return n in {1093, 3511}
|
|
1886
|
+
|
|
1887
|
+
|
|
1888
|
+
@register(
|
|
1889
|
+
name="Wall-Sun-Sun Prime",
|
|
1890
|
+
category="primes",
|
|
1891
|
+
oeis="A007732",
|
|
1892
|
+
description=(
|
|
1893
|
+
"A prime p where the Fibonacci number F(p) ≡ (p/5) (mod p²), "
|
|
1894
|
+
"where (p/5) is the Legendre symbol. None are currently known."
|
|
1895
|
+
),
|
|
1896
|
+
aliases=["wall_sun_sun_prime"],
|
|
1897
|
+
)
|
|
1898
|
+
def is_wall_sun_sun_prime(n: int) -> bool:
|
|
1899
|
+
"""Return ``True`` if *n* is a Wall-Sun-Sun prime.
|
|
1900
|
+
|
|
1901
|
+
A Wall-Sun-Sun prime (also called a Fibonacci-Wieferich prime) is a prime
|
|
1902
|
+
*p* such that ``F(p) ≡ (p | 5) (mod p²)``, where ``(p | 5)`` is the
|
|
1903
|
+
Legendre symbol and ``F(p)`` is the *p*-th Fibonacci number.
|
|
1904
|
+
|
|
1905
|
+
**No Wall-Sun-Sun prime is currently known.** An extensive computational
|
|
1906
|
+
search has verified none exist below approximately 9.7 × 10¹⁴. This
|
|
1907
|
+
function therefore always returns ``False``.
|
|
1908
|
+
|
|
1909
|
+
Parameters
|
|
1910
|
+
----------
|
|
1911
|
+
n:
|
|
1912
|
+
Integer to test.
|
|
1913
|
+
|
|
1914
|
+
Returns
|
|
1915
|
+
-------
|
|
1916
|
+
bool
|
|
1917
|
+
Always ``False`` — no Wall-Sun-Sun prime is known.
|
|
1918
|
+
|
|
1919
|
+
Example
|
|
1920
|
+
-------
|
|
1921
|
+
>>> is_wall_sun_sun_prime(5)
|
|
1922
|
+
False
|
|
1923
|
+
>>> is_wall_sun_sun_prime(1000003)
|
|
1924
|
+
False
|
|
1925
|
+
"""
|
|
1926
|
+
return False
|
|
1927
|
+
|
|
1928
|
+
|
|
1929
|
+
@register(
|
|
1930
|
+
name="Wolstenholme Prime",
|
|
1931
|
+
category="primes",
|
|
1932
|
+
oeis="A088164",
|
|
1933
|
+
description=(
|
|
1934
|
+
"A prime p where C(2p, p) ≡ 2 (mod p⁴). "
|
|
1935
|
+
"Only two are known: 16843, 2124679."
|
|
1936
|
+
),
|
|
1937
|
+
aliases=["wolstenholme_prime"],
|
|
1938
|
+
)
|
|
1939
|
+
def is_wolstenholme_prime(n: int) -> bool:
|
|
1940
|
+
"""Return ``True`` if *n* is a Wolstenholme prime.
|
|
1941
|
+
|
|
1942
|
+
A Wolstenholme prime is a prime *p* for which the central binomial
|
|
1943
|
+
coefficient ``C(2p, p) ≡ 2 (mod p⁴)``. Only two are known: 16843 and
|
|
1944
|
+
2124679.
|
|
1945
|
+
|
|
1946
|
+
This function checks membership in the known set rather than computing
|
|
1947
|
+
the binomial coefficient (which grows astronomically).
|
|
1948
|
+
|
|
1949
|
+
Parameters
|
|
1950
|
+
----------
|
|
1951
|
+
n:
|
|
1952
|
+
Integer to test.
|
|
1953
|
+
|
|
1954
|
+
Returns
|
|
1955
|
+
-------
|
|
1956
|
+
bool
|
|
1957
|
+
|
|
1958
|
+
Example
|
|
1959
|
+
-------
|
|
1960
|
+
>>> is_wolstenholme_prime(16843)
|
|
1961
|
+
True
|
|
1962
|
+
>>> is_wolstenholme_prime(2124679)
|
|
1963
|
+
True
|
|
1964
|
+
>>> is_wolstenholme_prime(7)
|
|
1965
|
+
False
|
|
1966
|
+
|
|
1967
|
+
Notes
|
|
1968
|
+
-----
|
|
1969
|
+
All primes up to approximately 10⁹ have been checked; no others are known.
|
|
1970
|
+
"""
|
|
1971
|
+
return n in {16843, 2124679}
|
|
1972
|
+
|
|
1973
|
+
|
|
1974
|
+
def _lucky_numbers_up_to(n: int) -> frozenset:
|
|
1975
|
+
"""Return the set of lucky numbers up to *n* via the lucky-number sieve.
|
|
1976
|
+
|
|
1977
|
+
The sieve starts with odd positive integers [1, 3, 5, 7, …] and
|
|
1978
|
+
repeatedly removes every *k*-th remaining element where *k* is the second
|
|
1979
|
+
element (3), then third element (7), and so on.
|
|
1980
|
+
|
|
1981
|
+
Parameters
|
|
1982
|
+
----------
|
|
1983
|
+
n:
|
|
1984
|
+
Upper bound (inclusive).
|
|
1985
|
+
|
|
1986
|
+
Returns
|
|
1987
|
+
-------
|
|
1988
|
+
frozenset[int]
|
|
1989
|
+
"""
|
|
1990
|
+
if n < 1:
|
|
1991
|
+
return frozenset()
|
|
1992
|
+
# Start with odd numbers
|
|
1993
|
+
sieve = list(range(1, n + 1, 2))
|
|
1994
|
+
idx = 1 # Start with the second element
|
|
1995
|
+
while idx < len(sieve):
|
|
1996
|
+
step = sieve[idx]
|
|
1997
|
+
# Remove every step-th element (1-indexed)
|
|
1998
|
+
sieve = [v for i, v in enumerate(sieve) if (i + 1) % step != 0]
|
|
1999
|
+
idx += 1
|
|
2000
|
+
if idx >= len(sieve):
|
|
2001
|
+
break
|
|
2002
|
+
return frozenset(sieve)
|
|
2003
|
+
|
|
2004
|
+
|
|
2005
|
+
@register(
|
|
2006
|
+
name="Lucky Prime",
|
|
2007
|
+
category="primes",
|
|
2008
|
+
oeis="A031157",
|
|
2009
|
+
description=(
|
|
2010
|
+
"A number that is both prime and a lucky number."
|
|
2011
|
+
),
|
|
2012
|
+
aliases=["lucky_prime"],
|
|
2013
|
+
)
|
|
2014
|
+
def is_lucky_prime(n: int) -> bool:
|
|
2015
|
+
"""Return ``True`` if *n* is a lucky prime.
|
|
2016
|
+
|
|
2017
|
+
A lucky prime is a number that belongs to both the sequence of primes and
|
|
2018
|
+
the sequence of lucky numbers. Lucky numbers are generated by a sieve
|
|
2019
|
+
similar to the Sieve of Eratosthenes applied to the odd positive integers.
|
|
2020
|
+
|
|
2021
|
+
Parameters
|
|
2022
|
+
----------
|
|
2023
|
+
n:
|
|
2024
|
+
Integer to test.
|
|
2025
|
+
|
|
2026
|
+
Returns
|
|
2027
|
+
-------
|
|
2028
|
+
bool
|
|
2029
|
+
|
|
2030
|
+
Example
|
|
2031
|
+
-------
|
|
2032
|
+
>>> is_lucky_prime(3)
|
|
2033
|
+
True
|
|
2034
|
+
>>> is_lucky_prime(7)
|
|
2035
|
+
True
|
|
2036
|
+
>>> is_lucky_prime(13)
|
|
2037
|
+
True
|
|
2038
|
+
>>> is_lucky_prime(5) # 5 is prime but not lucky
|
|
2039
|
+
False
|
|
2040
|
+
|
|
2041
|
+
Edge cases
|
|
2042
|
+
----------
|
|
2043
|
+
* ``n <= 1`` returns ``False``.
|
|
2044
|
+
"""
|
|
2045
|
+
if not is_prime(n):
|
|
2046
|
+
return False
|
|
2047
|
+
lucky = _lucky_numbers_up_to(n)
|
|
2048
|
+
return n in lucky
|
|
2049
|
+
|
|
2050
|
+
|
|
2051
|
+
# ---------------------------------------------------------------------------
|
|
2052
|
+
# GROUP 5 (partial) — Semiprime (registered)
|
|
2053
|
+
# ---------------------------------------------------------------------------
|
|
2054
|
+
|
|
2055
|
+
@register(
|
|
2056
|
+
name="Semiprime",
|
|
2057
|
+
category="primes",
|
|
2058
|
+
oeis="A001358",
|
|
2059
|
+
description=(
|
|
2060
|
+
"A natural number that is the product of exactly two prime numbers "
|
|
2061
|
+
"(not necessarily distinct)."
|
|
2062
|
+
),
|
|
2063
|
+
aliases=["semiprime"],
|
|
2064
|
+
)
|
|
2065
|
+
def is_semiprime(n: int) -> bool:
|
|
2066
|
+
"""Return ``True`` if *n* is a semiprime.
|
|
2067
|
+
|
|
2068
|
+
A semiprime is a natural number that is the product of exactly two primes,
|
|
2069
|
+
counting multiplicity. Equivalently, its prime factorisation has exactly
|
|
2070
|
+
two factors (e.g. 4 = 2×2, 6 = 2×3, 9 = 3×3, 15 = 3×5).
|
|
2071
|
+
|
|
2072
|
+
Parameters
|
|
2073
|
+
----------
|
|
2074
|
+
n:
|
|
2075
|
+
Integer to test.
|
|
2076
|
+
|
|
2077
|
+
Returns
|
|
2078
|
+
-------
|
|
2079
|
+
bool
|
|
2080
|
+
|
|
2081
|
+
Example
|
|
2082
|
+
-------
|
|
2083
|
+
>>> is_semiprime(4) # 2 * 2
|
|
2084
|
+
True
|
|
2085
|
+
>>> is_semiprime(6) # 2 * 3
|
|
2086
|
+
True
|
|
2087
|
+
>>> is_semiprime(9) # 3 * 3
|
|
2088
|
+
True
|
|
2089
|
+
>>> is_semiprime(12) # 2 * 2 * 3 — three factors
|
|
2090
|
+
False
|
|
2091
|
+
>>> is_semiprime(7) # prime — one factor
|
|
2092
|
+
False
|
|
2093
|
+
|
|
2094
|
+
Edge cases
|
|
2095
|
+
----------
|
|
2096
|
+
* ``n <= 1`` returns ``False``.
|
|
2097
|
+
"""
|
|
2098
|
+
if n <= 1:
|
|
2099
|
+
return False
|
|
2100
|
+
return len(prime_factors(n)) == 2
|