Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
122
Task/Cyclotomic-polynomial/Python/cyclotomic-polynomial.py
Normal file
122
Task/Cyclotomic-polynomial/Python/cyclotomic-polynomial.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
from itertools import count, chain
|
||||
from collections import deque
|
||||
|
||||
def primes(_cache=[2, 3]):
|
||||
yield from _cache
|
||||
for n in count(_cache[-1]+2, 2):
|
||||
if isprime(n):
|
||||
_cache.append(n)
|
||||
yield n
|
||||
|
||||
def isprime(n):
|
||||
for p in primes():
|
||||
if n%p == 0:
|
||||
return False
|
||||
if p*p > n:
|
||||
return True
|
||||
|
||||
def factors(n):
|
||||
for p in primes():
|
||||
# prime factoring is such a non-issue for small numbers that, for
|
||||
# this example, we might even just say
|
||||
# for p in count(2):
|
||||
if p*p > n:
|
||||
if n > 1:
|
||||
yield(n, 1, 1)
|
||||
break
|
||||
|
||||
if n%p == 0:
|
||||
cnt = 0
|
||||
while True:
|
||||
n, cnt = n//p, cnt+1
|
||||
if n%p != 0: break
|
||||
yield p, cnt, n
|
||||
# ^^ not the most sophisticated prime number routines, because no need
|
||||
|
||||
# Returns (list1, list2) representing the division between
|
||||
# two polinomials. A list p of integers means the product
|
||||
# (x^p[0] - 1) * (x^p[1] - 1) * ...
|
||||
def cyclotomic(n):
|
||||
def poly_div(num, den):
|
||||
return (num[0] + den[1], num[1] + den[0])
|
||||
|
||||
def elevate(poly, n): # replace poly p(x) with p(x**n)
|
||||
powerup = lambda p, n: [a*n for a in p]
|
||||
return poly if n == 1 else (powerup(poly[0], n), powerup(poly[1], n))
|
||||
|
||||
|
||||
if n == 0:
|
||||
return ([], [])
|
||||
if n == 1:
|
||||
return ([1], [])
|
||||
|
||||
p, m, r = next(factors(n))
|
||||
poly = cyclotomic(r)
|
||||
return elevate(poly_div(elevate(poly, p), poly), p**(m-1))
|
||||
|
||||
def to_text(poly):
|
||||
def getx(c, e):
|
||||
if e == 0:
|
||||
return '1'
|
||||
elif e == 1:
|
||||
return 'x'
|
||||
return 'x' + (''.join('⁰¹²³⁴⁵⁶⁷⁸⁹'[i] for i in map(int, str(e))))
|
||||
|
||||
parts = []
|
||||
for (c,e) in (poly):
|
||||
if c < 0:
|
||||
coef = ' - ' if c == -1 else f' - {-c} '
|
||||
else:
|
||||
coef = (parts and ' + ' or '') if c == 1 else f' + {c}'
|
||||
parts.append(coef + getx(c,e))
|
||||
return ''.join(parts)
|
||||
|
||||
def terms(poly):
|
||||
# convert above representation of division to (coef, power) pairs
|
||||
|
||||
def merge(a, b):
|
||||
# a, b should be deques. They may change during the course.
|
||||
while a or b:
|
||||
l = a[0] if a else (0, -1) # sentinel value
|
||||
r = b[0] if b else (0, -1)
|
||||
if l[1] > r[1]:
|
||||
a.popleft()
|
||||
elif l[1] < r[1]:
|
||||
b.popleft()
|
||||
l = r
|
||||
else:
|
||||
a.popleft()
|
||||
b.popleft()
|
||||
l = (l[0] + r[0], l[1])
|
||||
yield l
|
||||
|
||||
def mul(poly, p): # p means polynomial x^p - 1
|
||||
poly = list(poly)
|
||||
return merge(deque((c, e+p) for c,e in poly),
|
||||
deque((-c, e) for c,e in poly))
|
||||
|
||||
def div(poly, p): # p means polynomial x^p - 1
|
||||
q = deque()
|
||||
for c,e in merge(deque(poly), q):
|
||||
if c:
|
||||
q.append((c, e - p))
|
||||
yield (c, e - p)
|
||||
if e == p: break
|
||||
|
||||
p = [(1, 0)] # 1*x^0, i.e. 1
|
||||
|
||||
for x in poly[0]: # numerator
|
||||
p = mul(p, x)
|
||||
for x in sorted(poly[1], reverse=True): # denominator
|
||||
p = div(p, x)
|
||||
return p
|
||||
|
||||
for n in chain(range(11), [2]):
|
||||
print(f'{n}: {to_text(terms(cyclotomic(n)))}')
|
||||
|
||||
want = 1
|
||||
for n in count():
|
||||
c = [c for c,_ in terms(cyclotomic(n))]
|
||||
while want in c or -want in c:
|
||||
print(f'C[{want}]: {n}')
|
||||
want += 1
|
||||
Loading…
Add table
Add a link
Reference in a new issue