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,349 @@
|
|
|
1
|
+
"""
|
|
2
|
+
numclassify/_core/powers.py
|
|
3
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
4
|
+
Power-based number classification functions.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import math
|
|
9
|
+
from typing import Set
|
|
10
|
+
|
|
11
|
+
from numclassify._registry import register
|
|
12
|
+
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
# Helper (NOT registered)
|
|
15
|
+
# ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
def is_perfect_power_check(n: int, exp: int) -> bool:
|
|
18
|
+
"""Return True if n is a perfect exp-th power (n = k^exp for integer k > 0).
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
n : int
|
|
23
|
+
exp : int
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
bool
|
|
28
|
+
"""
|
|
29
|
+
if n < 0 or exp < 2:
|
|
30
|
+
return False
|
|
31
|
+
if n == 0 or n == 1:
|
|
32
|
+
return True
|
|
33
|
+
root = round(n ** (1.0 / exp))
|
|
34
|
+
for r in range(max(1, root - 2), root + 3):
|
|
35
|
+
if r ** exp == n:
|
|
36
|
+
return True
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# ---------------------------------------------------------------------------
|
|
41
|
+
# Registered classifiers
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
@register(name="Perfect Square", category="powers", oeis="A000290",
|
|
45
|
+
description="n = k^2 for some non-negative integer k.")
|
|
46
|
+
def is_perfect_square(n: int) -> bool:
|
|
47
|
+
"""Return True if n is a perfect square.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
n : int
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
bool
|
|
56
|
+
|
|
57
|
+
Examples
|
|
58
|
+
--------
|
|
59
|
+
>>> is_perfect_square(16)
|
|
60
|
+
True
|
|
61
|
+
>>> is_perfect_square(15)
|
|
62
|
+
False
|
|
63
|
+
"""
|
|
64
|
+
if n < 0:
|
|
65
|
+
return False
|
|
66
|
+
r = math.isqrt(n)
|
|
67
|
+
return r * r == n
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@register(name="Perfect Cube", category="powers", oeis="A000578",
|
|
71
|
+
description="n = k^3 for some positive integer k.")
|
|
72
|
+
def is_perfect_cube(n: int) -> bool:
|
|
73
|
+
"""Return True if n is a perfect cube.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
n : int
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
bool
|
|
82
|
+
|
|
83
|
+
Examples
|
|
84
|
+
--------
|
|
85
|
+
>>> is_perfect_cube(27)
|
|
86
|
+
True
|
|
87
|
+
>>> is_perfect_cube(26)
|
|
88
|
+
False
|
|
89
|
+
"""
|
|
90
|
+
if n < 0:
|
|
91
|
+
return False
|
|
92
|
+
return is_perfect_power_check(n, 3)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@register(name="Perfect Fourth Power", category="powers", oeis="A000583",
|
|
96
|
+
description="n = k^4 for some positive integer k.")
|
|
97
|
+
def is_perfect_fourth(n: int) -> bool:
|
|
98
|
+
"""Return True if n is a perfect fourth power.
|
|
99
|
+
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
n : int
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
bool
|
|
107
|
+
"""
|
|
108
|
+
if n < 0:
|
|
109
|
+
return False
|
|
110
|
+
return is_perfect_power_check(n, 4)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@register(name="Perfect Fifth Power", category="powers", oeis="A000584",
|
|
114
|
+
description="n = k^5 for some positive integer k.")
|
|
115
|
+
def is_perfect_fifth(n: int) -> bool:
|
|
116
|
+
"""Return True if n is a perfect fifth power.
|
|
117
|
+
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
n : int
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
bool
|
|
125
|
+
"""
|
|
126
|
+
if n < 0:
|
|
127
|
+
return False
|
|
128
|
+
return is_perfect_power_check(n, 5)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@register(name="Perfect Power", category="powers", oeis="A001597",
|
|
132
|
+
description="n = k^m for some integers k > 1, m > 1.")
|
|
133
|
+
def is_perfect_power(n: int) -> bool:
|
|
134
|
+
"""Return True if n is a perfect power (k^m, k>1, m>1).
|
|
135
|
+
|
|
136
|
+
Parameters
|
|
137
|
+
----------
|
|
138
|
+
n : int
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
bool
|
|
143
|
+
"""
|
|
144
|
+
if n <= 1:
|
|
145
|
+
return False
|
|
146
|
+
for exp in range(2, n.bit_length() + 1):
|
|
147
|
+
if is_perfect_power_check(n, exp):
|
|
148
|
+
return True
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@register(name="Sum of Two Squares", category="powers", oeis="A001481",
|
|
153
|
+
description="n = a^2 + b^2 for non-negative integers a, b.")
|
|
154
|
+
def is_sum_of_two_squares(n: int) -> bool:
|
|
155
|
+
"""Return True if n can be expressed as the sum of two squares.
|
|
156
|
+
|
|
157
|
+
Parameters
|
|
158
|
+
----------
|
|
159
|
+
n : int
|
|
160
|
+
|
|
161
|
+
Returns
|
|
162
|
+
-------
|
|
163
|
+
bool
|
|
164
|
+
|
|
165
|
+
Examples
|
|
166
|
+
--------
|
|
167
|
+
>>> is_sum_of_two_squares(5)
|
|
168
|
+
True
|
|
169
|
+
>>> is_sum_of_two_squares(3)
|
|
170
|
+
False
|
|
171
|
+
"""
|
|
172
|
+
if n < 0:
|
|
173
|
+
return False
|
|
174
|
+
a = 0
|
|
175
|
+
while a * a <= n:
|
|
176
|
+
remainder = n - a * a
|
|
177
|
+
b = math.isqrt(remainder)
|
|
178
|
+
if b * b == remainder:
|
|
179
|
+
return True
|
|
180
|
+
a += 1
|
|
181
|
+
return False
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@register(name="Sum of Two Cubes", category="powers", oeis="A003325",
|
|
185
|
+
description="n = a^3 + b^3 for positive integers a, b.")
|
|
186
|
+
def is_sum_of_two_cubes(n: int) -> bool:
|
|
187
|
+
"""Return True if n can be expressed as the sum of two positive cubes.
|
|
188
|
+
|
|
189
|
+
Parameters
|
|
190
|
+
----------
|
|
191
|
+
n : int
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
bool
|
|
196
|
+
"""
|
|
197
|
+
if n < 2:
|
|
198
|
+
return False
|
|
199
|
+
a = 1
|
|
200
|
+
while a ** 3 < n:
|
|
201
|
+
remainder = n - a ** 3
|
|
202
|
+
b = round(remainder ** (1.0 / 3))
|
|
203
|
+
for r in range(max(1, b - 1), b + 2):
|
|
204
|
+
if r ** 3 == remainder:
|
|
205
|
+
return True
|
|
206
|
+
a += 1
|
|
207
|
+
return False
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@register(name="Sum of Three Squares", category="powers", oeis="A000443",
|
|
211
|
+
description="n = a^2 + b^2 + c^2 (by Legendre's three-square theorem).")
|
|
212
|
+
def is_sum_of_three_squares(n: int) -> bool:
|
|
213
|
+
"""Return True if n can be expressed as the sum of three squares.
|
|
214
|
+
|
|
215
|
+
Uses Legendre's three-square theorem: n is NOT expressible iff
|
|
216
|
+
n = 4^a * (8b + 7) for non-negative integers a, b.
|
|
217
|
+
|
|
218
|
+
Parameters
|
|
219
|
+
----------
|
|
220
|
+
n : int
|
|
221
|
+
|
|
222
|
+
Returns
|
|
223
|
+
-------
|
|
224
|
+
bool
|
|
225
|
+
"""
|
|
226
|
+
if n < 0:
|
|
227
|
+
return False
|
|
228
|
+
# Remove factors of 4
|
|
229
|
+
while n % 4 == 0:
|
|
230
|
+
n //= 4
|
|
231
|
+
return n % 8 != 7
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@register(name="Taxicab", category="powers", oeis="A001235",
|
|
235
|
+
description="Expressible as sum of two cubes in at least 2 different ways.")
|
|
236
|
+
def is_taxicab(n: int) -> bool:
|
|
237
|
+
"""Return True if n can be expressed as the sum of two positive cubes in ≥ 2 ways.
|
|
238
|
+
|
|
239
|
+
Parameters
|
|
240
|
+
----------
|
|
241
|
+
n : int
|
|
242
|
+
|
|
243
|
+
Returns
|
|
244
|
+
-------
|
|
245
|
+
bool
|
|
246
|
+
|
|
247
|
+
Examples
|
|
248
|
+
--------
|
|
249
|
+
>>> is_taxicab(1729)
|
|
250
|
+
True
|
|
251
|
+
"""
|
|
252
|
+
if n < 2:
|
|
253
|
+
return False
|
|
254
|
+
ways = 0
|
|
255
|
+
a = 1
|
|
256
|
+
while a ** 3 < n:
|
|
257
|
+
remainder = n - a ** 3
|
|
258
|
+
b = round(remainder ** (1.0 / 3))
|
|
259
|
+
for r in range(max(1, b - 1), b + 2):
|
|
260
|
+
if r >= a and r ** 3 == remainder:
|
|
261
|
+
ways += 1
|
|
262
|
+
break
|
|
263
|
+
a += 1
|
|
264
|
+
return ways >= 2
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@register(name="Power of 2", category="powers", oeis="A000079",
|
|
268
|
+
description="n = 2^k for some non-negative integer k.")
|
|
269
|
+
def is_power_of_2(n: int) -> bool:
|
|
270
|
+
"""Return True if n is a power of 2.
|
|
271
|
+
|
|
272
|
+
Parameters
|
|
273
|
+
----------
|
|
274
|
+
n : int
|
|
275
|
+
|
|
276
|
+
Returns
|
|
277
|
+
-------
|
|
278
|
+
bool
|
|
279
|
+
"""
|
|
280
|
+
return n > 0 and (n & (n - 1)) == 0
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
@register(name="Power of 3", category="powers", oeis="A000244",
|
|
284
|
+
description="n = 3^k for some non-negative integer k.")
|
|
285
|
+
def is_power_of_3(n: int) -> bool:
|
|
286
|
+
"""Return True if n is a power of 3.
|
|
287
|
+
|
|
288
|
+
Parameters
|
|
289
|
+
----------
|
|
290
|
+
n : int
|
|
291
|
+
|
|
292
|
+
Returns
|
|
293
|
+
-------
|
|
294
|
+
bool
|
|
295
|
+
"""
|
|
296
|
+
if n < 1:
|
|
297
|
+
return False
|
|
298
|
+
while n % 3 == 0:
|
|
299
|
+
n //= 3
|
|
300
|
+
return n == 1
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
@register(name="Power of 10", category="powers", oeis="A011557",
|
|
304
|
+
description="n = 10^k for some non-negative integer k.")
|
|
305
|
+
def is_power_of_10(n: int) -> bool:
|
|
306
|
+
"""Return True if n is a power of 10.
|
|
307
|
+
|
|
308
|
+
Parameters
|
|
309
|
+
----------
|
|
310
|
+
n : int
|
|
311
|
+
|
|
312
|
+
Returns
|
|
313
|
+
-------
|
|
314
|
+
bool
|
|
315
|
+
"""
|
|
316
|
+
if n < 1:
|
|
317
|
+
return False
|
|
318
|
+
while n % 10 == 0:
|
|
319
|
+
n //= 10
|
|
320
|
+
return n == 1
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
@register(name="Sum of Squares of Primes", category="powers",
|
|
324
|
+
description="n = p1^2 + p2^2 for primes p1, p2.")
|
|
325
|
+
def is_sum_of_squares_of_primes(n: int) -> bool:
|
|
326
|
+
"""Return True if n = p1^2 + p2^2 for primes p1, p2.
|
|
327
|
+
|
|
328
|
+
Parameters
|
|
329
|
+
----------
|
|
330
|
+
n : int
|
|
331
|
+
|
|
332
|
+
Returns
|
|
333
|
+
-------
|
|
334
|
+
bool
|
|
335
|
+
"""
|
|
336
|
+
if n < 4:
|
|
337
|
+
return False
|
|
338
|
+
from numclassify._core.primes import is_prime
|
|
339
|
+
limit = math.isqrt(n)
|
|
340
|
+
p1 = 2
|
|
341
|
+
while p1 <= limit:
|
|
342
|
+
if is_prime(p1):
|
|
343
|
+
remainder = n - p1 * p1
|
|
344
|
+
if remainder > 0:
|
|
345
|
+
p2 = math.isqrt(remainder)
|
|
346
|
+
if p2 * p2 == remainder and is_prime(p2):
|
|
347
|
+
return True
|
|
348
|
+
p1 += 1 if p1 == 2 else 2
|
|
349
|
+
return False
|