2018-06-26 02:05:11 +02:00
|
|
|
import itertools
|
|
|
|
|
|
|
|
|
2018-06-27 19:14:55 +02:00
|
|
|
class Poly:
|
|
|
|
|
2018-06-27 22:09:17 +02:00
|
|
|
def __init__(self, int_mod, elements):
|
2018-06-27 19:14:55 +02:00
|
|
|
self.elements = {}
|
2018-06-27 22:09:17 +02:00
|
|
|
self.int_mod = int_mod
|
2018-06-27 19:14:55 +02:00
|
|
|
|
2018-06-28 01:46:46 +02:00
|
|
|
elements = list(reversed(elements))
|
|
|
|
z = 0
|
|
|
|
for i in elements:
|
|
|
|
if i != 0:
|
|
|
|
break
|
|
|
|
z += 1
|
|
|
|
elements = elements[z:]
|
|
|
|
|
2018-06-27 19:14:55 +02:00
|
|
|
i = len(elements) - 1
|
2018-06-28 01:46:46 +02:00
|
|
|
for e in elements:
|
2018-06-27 22:09:17 +02:00
|
|
|
self.elements[f"x{i}"] = e % self.int_mod
|
2018-06-27 19:14:55 +02:00
|
|
|
i -= 1
|
|
|
|
|
|
|
|
def __str__(self):
|
2018-06-27 22:09:17 +02:00
|
|
|
str_form = ""
|
|
|
|
deg = len(self.elements) - 1
|
|
|
|
|
|
|
|
for e in self.elements:
|
|
|
|
|
|
|
|
if self.elements[e] >= 0:
|
|
|
|
if e != f"x{deg}":
|
|
|
|
str_form += "+ "
|
|
|
|
else:
|
|
|
|
str_form += "- "
|
|
|
|
|
|
|
|
str_form += str(abs(self.elements[e]))
|
|
|
|
|
|
|
|
if e != "x0":
|
|
|
|
str_form += e[0] + "^" + e[1:] + " "
|
|
|
|
|
|
|
|
return str_form
|
2018-06-27 19:14:55 +02:00
|
|
|
|
|
|
|
def __mul__(self, other):
|
2018-06-27 22:09:17 +02:00
|
|
|
|
2018-06-27 23:04:58 +02:00
|
|
|
assert self.int_mod == other.int_mod
|
2018-06-27 22:09:17 +02:00
|
|
|
|
2018-06-27 19:14:55 +02:00
|
|
|
elements = {}
|
|
|
|
|
|
|
|
for e in self.elements:
|
|
|
|
for f in other.elements:
|
|
|
|
coefficient = self.elements[e] * other.elements[f]
|
|
|
|
degree = f"x{int(e[1:])+int(f[1:])}"
|
|
|
|
|
|
|
|
if elements.get(f"{degree}") is None:
|
2018-06-27 22:09:17 +02:00
|
|
|
elements[degree] = coefficient % self.int_mod
|
2018-06-27 19:14:55 +02:00
|
|
|
else:
|
2018-06-27 22:09:17 +02:00
|
|
|
elements[degree] += coefficient % self.int_mod
|
2018-06-27 19:14:55 +02:00
|
|
|
|
2018-06-28 00:06:30 +02:00
|
|
|
els = {}
|
|
|
|
for i in reversed(range(len(elements))):
|
|
|
|
els[f"x{i}"] = elements[f"x{i}"]
|
|
|
|
|
|
|
|
return Poly(self.int_mod, list(reversed(list(els.values()))))
|
2018-06-27 19:14:55 +02:00
|
|
|
|
2018-06-27 22:09:17 +02:00
|
|
|
def __pow__(self, power, modulo=None):
|
|
|
|
poly = Poly(self.int_mod, list(reversed(list(self.elements.values()))))
|
|
|
|
|
|
|
|
for i in range(power - 1):
|
|
|
|
poly *= poly
|
|
|
|
|
|
|
|
return poly
|
|
|
|
|
|
|
|
def __add__(self, other):
|
|
|
|
|
2018-06-27 23:04:58 +02:00
|
|
|
assert self.int_mod == other.int_mod
|
2018-06-27 22:09:17 +02:00
|
|
|
|
|
|
|
elements = self.elements.copy()
|
|
|
|
|
|
|
|
for f in other.elements:
|
|
|
|
if f in elements:
|
|
|
|
elements[f] += other.elements[f]
|
|
|
|
else:
|
|
|
|
elements[f] = other.elements[f]
|
|
|
|
|
2018-06-27 23:04:58 +02:00
|
|
|
els = {}
|
|
|
|
for i in reversed(range(len(elements))):
|
|
|
|
els[f"x{i}"] = elements[f"x{i}"]
|
|
|
|
|
|
|
|
return Poly(self.int_mod, list(reversed(list(els.values()))))
|
|
|
|
|
|
|
|
def __sub__(self, other):
|
|
|
|
|
|
|
|
assert self.int_mod == other.int_mod
|
|
|
|
|
|
|
|
elements = self.elements.copy()
|
|
|
|
|
|
|
|
for e in other.elements:
|
|
|
|
if e in elements:
|
|
|
|
elements[e] -= other.elements[e]
|
|
|
|
else:
|
|
|
|
elements[e] = -other.elements[e]
|
|
|
|
|
|
|
|
els = {}
|
|
|
|
for i in reversed(range(len(elements))):
|
|
|
|
els[f"x{i}"] = elements[f"x{i}"]
|
|
|
|
|
|
|
|
return Poly(self.int_mod, list(reversed(list(els.values()))))
|
2018-06-27 22:09:17 +02:00
|
|
|
|
|
|
|
def __truediv__(self, other):
|
|
|
|
|
2018-06-28 00:06:30 +02:00
|
|
|
assert self.int_mod == other.int_mod
|
2018-06-27 22:09:17 +02:00
|
|
|
|
|
|
|
if other.is_empty():
|
|
|
|
raise ZeroDivisionError("Polynomial is empty")
|
|
|
|
|
2018-06-28 00:06:30 +02:00
|
|
|
poly = Poly(self.int_mod, list(reversed(list(self.elements.values()))))
|
|
|
|
fdeg = len(poly.elements) - 1
|
2018-06-27 22:09:17 +02:00
|
|
|
sdeg = len(other.elements) - 1
|
2018-06-28 13:16:51 +02:00
|
|
|
|
|
|
|
els = {}
|
|
|
|
|
2018-06-28 00:06:30 +02:00
|
|
|
while fdeg >= sdeg:
|
2018-06-28 01:46:46 +02:00
|
|
|
coefficient = other.elements[f"x{sdeg}"]
|
|
|
|
for i in range(1, poly.int_mod):
|
2018-06-28 13:16:51 +02:00
|
|
|
if coefficient * i % poly.int_mod == poly.elements[f"x{fdeg}"]:
|
2018-06-28 01:46:46 +02:00
|
|
|
coefficient = i
|
|
|
|
break
|
|
|
|
|
2018-06-27 22:09:17 +02:00
|
|
|
degree = fdeg - sdeg
|
|
|
|
|
2018-06-28 00:06:30 +02:00
|
|
|
divpoly = [0 for x in range(degree + 1)]
|
|
|
|
divpoly[degree] = coefficient
|
|
|
|
divpoly = Poly(poly.int_mod, divpoly)
|
2018-06-28 13:16:51 +02:00
|
|
|
els[f"x{degree}"] = coefficient
|
2018-06-28 00:06:30 +02:00
|
|
|
|
|
|
|
mulpoly = divpoly * other
|
2018-06-28 13:16:51 +02:00
|
|
|
|
2018-06-28 00:06:30 +02:00
|
|
|
poly -= mulpoly
|
2018-06-28 13:16:51 +02:00
|
|
|
|
2018-06-28 00:06:30 +02:00
|
|
|
for i in poly.elements.keys():
|
|
|
|
if poly.elements[f"{i}"] != 0:
|
|
|
|
fdeg = int(i[1:])
|
|
|
|
break
|
|
|
|
|
2018-06-28 13:16:51 +02:00
|
|
|
return Poly(poly.int_mod, list(reversed(list(els.values()))))
|
2018-06-27 22:09:17 +02:00
|
|
|
|
2018-06-28 01:46:46 +02:00
|
|
|
def __mod__(self, other):
|
|
|
|
|
2018-06-28 13:16:51 +02:00
|
|
|
assert self.int_mod == other.int_mod
|
|
|
|
|
|
|
|
if other.is_empty():
|
|
|
|
raise ZeroDivisionError("Polynomial is empty")
|
|
|
|
|
|
|
|
poly = Poly(self.int_mod, list(reversed(list(self.elements.values()))))
|
|
|
|
fdeg = len(poly.elements) - 1
|
|
|
|
sdeg = len(other.elements) - 1
|
|
|
|
|
|
|
|
while fdeg >= sdeg:
|
|
|
|
coefficient = other.elements[f"x{sdeg}"]
|
|
|
|
for i in range(1, poly.int_mod):
|
|
|
|
if coefficient * i % poly.int_mod == poly.elements[f"x{fdeg}"]:
|
|
|
|
coefficient = i
|
|
|
|
break
|
|
|
|
|
|
|
|
degree = fdeg - sdeg
|
|
|
|
|
|
|
|
divpoly = [0 for x in range(degree + 1)]
|
|
|
|
divpoly[degree] = coefficient
|
|
|
|
divpoly = Poly(poly.int_mod, divpoly)
|
|
|
|
|
|
|
|
mulpoly = divpoly * other
|
|
|
|
|
|
|
|
poly -= mulpoly
|
|
|
|
|
|
|
|
for i in poly.elements.keys():
|
|
|
|
if poly.elements[f"{i}"] != 0:
|
|
|
|
fdeg = int(i[1:])
|
|
|
|
break
|
|
|
|
|
|
|
|
return poly
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def gcd(self, other):
|
|
|
|
|
2018-06-28 01:46:46 +02:00
|
|
|
dividened = Poly(self.int_mod,
|
|
|
|
list(reversed(list(self.elements.values()))))
|
|
|
|
divisor = Poly(self.int_mod,
|
|
|
|
list(reversed(list(other.elements.values()))))
|
|
|
|
div_result = dividened / divisor
|
|
|
|
|
2018-06-28 13:16:51 +02:00
|
|
|
while True:
|
|
|
|
xs_zero = True
|
|
|
|
for e in div_result.elements:
|
|
|
|
if e != "x0":
|
|
|
|
if div_result.elements[e] != 0:
|
|
|
|
xs_zero = False
|
|
|
|
break
|
|
|
|
|
|
|
|
# if xs_zero:
|
|
|
|
# if div_result.elements["x0"] == 1:
|
|
|
|
# break
|
|
|
|
if dividened.is_empty():
|
|
|
|
break
|
|
|
|
|
|
|
|
dividened = Poly(dividened.int_mod,
|
|
|
|
list(reversed(list(divisor.elements.values()))))
|
|
|
|
divisor = Poly(divisor.int_mod,
|
|
|
|
list(reversed(list(div_result.elements.values()))))
|
|
|
|
div_result = dividened / divisor
|
|
|
|
|
2018-06-28 01:46:46 +02:00
|
|
|
return div_result
|
|
|
|
|
2018-06-27 22:09:17 +02:00
|
|
|
def is_empty(self):
|
|
|
|
|
|
|
|
for e in self.elements:
|
|
|
|
if self.elements[e] != 0:
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2018-06-26 02:05:11 +02:00
|
|
|
class PolyIntField:
|
|
|
|
|
2018-06-27 22:09:17 +02:00
|
|
|
def __init__(self, int_mod, poly_mod):
|
|
|
|
self.int_modulo = int_mod
|
|
|
|
self.poly_modulo = Poly(int_mod, poly_mod)
|
|
|
|
product = list(itertools.product([x for x in range(0, int_mod)],
|
|
|
|
repeat=len(poly_mod) - 1))
|
|
|
|
|
|
|
|
self.elements = []
|
|
|
|
for p in product:
|
|
|
|
p = list(p)
|
|
|
|
p = [x % int_mod for x in p]
|
|
|
|
self.elements.append(Poly(int_mod, p))
|
|
|
|
|
2018-06-26 02:05:11 +02:00
|
|
|
|
2018-06-28 13:16:51 +02:00
|
|
|
def invertibles(self):
|
|
|
|
invertibles = []
|
|
|
|
|
|
|
|
for e in self.elements:
|
|
|
|
if Poly.gcd(e, self.poly_modulo) == 1:
|
|
|
|
invertibles.append(e)
|
|
|
|
|
|
|
|
return invertibles
|
|
|
|
|
|
|
|
def nilpotents(self):
|
2018-06-27 19:14:55 +02:00
|
|
|
nilpotents = []
|
|
|
|
|
2018-06-28 13:16:51 +02:00
|
|
|
for e in self.elements:
|
|
|
|
if not e.is_empty():
|
|
|
|
for f in self.elements:
|
|
|
|
if not f.is_empty():
|
|
|
|
if (e ** f) % self.poly_modulo == e:
|
|
|
|
nilpotents.append(e)
|
|
|
|
|
|
|
|
return nilpotents
|
|
|
|
|
|
|
|
def idempotents(self):
|
|
|
|
idempotents = []
|
|
|
|
|
|
|
|
for e in self.elements:
|
|
|
|
if Poly.gcd((e ** 2), self.poly_modulo) == e:
|
|
|
|
idempotents.append(e)
|
|
|
|
|
|
|
|
return idempotents
|
|
|
|
|
|
|
|
def zero_divisors(self):
|
|
|
|
zero_divisors = []
|
|
|
|
|
|
|
|
for e in self.elements:
|
|
|
|
if not e.is_empty():
|
|
|
|
for f in self.elements:
|
|
|
|
if not f.is_empty():
|
|
|
|
if Poly.gcd((e * f), self.poly_modulo).is_empty():
|
|
|
|
zero_divisors.append(e)
|
|
|
|
|
|
|
|
return zero_divisors
|
2018-06-27 19:14:55 +02:00
|
|
|
|
|
|
|
|
2018-06-26 02:05:11 +02:00
|
|
|
if __name__ == "__main__":
|
2018-06-28 13:16:51 +02:00
|
|
|
|
|
|
|
# poly_field = PolyIntField(3, [1, 1, 2, 2])
|
|
|
|
# print(poly_field.invertibles())
|
|
|
|
# for p in poly_field.elements:
|
|
|
|
# print(p)
|
|
|
|
# print(p.elements)
|
|
|
|
# print(len(poly_field.elements))
|
|
|
|
# a = Poly(3, [0, 0, 0])
|
|
|
|
# b = Poly(3, [1, 2])
|
|
|
|
# print((a * b).is_empty())
|
|
|
|
|
|
|
|
# x = Poly(5, [1, 0, 4, 0, 2, 1])
|
|
|
|
# y = Poly(5, [4, 0, 0, 0, 1])
|
|
|
|
# print(x % y)
|
|
|
|
|
|
|
|
# o = Poly(5, [1, 0, 1, 2, 2, 1])
|
|
|
|
# print(o)
|
|
|
|
#
|
|
|
|
# p = Poly(5, [4, 0, 0, 0, 1])
|
|
|
|
# print(p)
|
|
|
|
# print(o / p)
|
|
|
|
|
|
|
|
# n = Poly(5, [1, 0, 1])
|
|
|
|
# m = Poly(5, [2, 4])
|
|
|
|
# print(n / m)
|
2018-06-28 01:46:46 +02:00
|
|
|
# a = Poly(5, [1, 0, 4, 0, 2, 1, 0, 0])
|
|
|
|
# # print(a)
|
|
|
|
# b = Poly(5, [4, 0, 0, 0, 1])
|
|
|
|
# # print(b)
|
|
|
|
# # print(a + b)
|
|
|
|
# print(a % b)
|
|
|
|
|
|
|
|
# d = Poly(5, [3, 1, 4])
|
|
|
|
# # print(d)
|
|
|
|
# e = Poly(5, [4, 0, 0, 0, 1])
|
|
|
|
# # print(e)
|
|
|
|
# print(e / d)
|
2018-06-28 13:16:51 +02:00
|
|
|
|
|
|
|
|
2018-06-28 01:46:46 +02:00
|
|
|
# c = Poly(5, [4, 0, 0, 0, 1])
|
|
|
|
# d = Poly(5, [3, 1, 4, 0, 0, 0])
|
|
|
|
# print(c)
|
|
|
|
# print(d)
|
|
|
|
# print(c % d)
|
|
|
|
|
2018-06-28 13:16:51 +02:00
|
|
|
e = Poly(10, [-4, 0, -2, 1])
|
|
|
|
f = Poly(10, [-3, 1])
|
|
|
|
print(e / f)
|
|
|
|
print(e % f)
|
|
|
|
print(f / e)
|
|
|
|
print(f % e)
|
2018-06-28 00:06:30 +02:00
|
|
|
|
2018-06-28 01:46:46 +02:00
|
|
|
# print((a % b).elements)
|
|
|
|
# d = Poly(10, [2, 0, 6, 0, 1])
|
|
|
|
# e = Poly(10, [5, 0, 1])
|
|
|
|
# print(d / e)
|
2018-06-28 00:06:30 +02:00
|
|
|
# print(a - Poly(10, [0, 0, -3, 1]))
|
|
|
|
# p = Poly(5, [-4, 0, -2, 1])
|
2018-06-27 22:09:17 +02:00
|
|
|
# print(p)
|
|
|
|
# c = p * p
|
|
|
|
# print(c.elements)
|
|
|
|
# print(c)
|
|
|
|
# print(p ** 2)
|
2018-06-27 23:04:58 +02:00
|
|
|
|
2018-06-27 22:09:17 +02:00
|
|
|
# print(p)
|
|
|
|
# print(d)
|
|
|
|
# print(p)
|
|
|
|
# print(p + d)
|
2018-06-28 00:06:30 +02:00
|
|
|
# d = Poly(5, [-3, 1])
|
|
|
|
# g = Poly(5, [1, 2, 1])
|
2018-06-27 23:04:58 +02:00
|
|
|
# print(d)
|
|
|
|
# print(g)
|
2018-06-28 00:06:30 +02:00
|
|
|
# print()
|
|
|
|
#
|
|
|
|
# # print(g)
|
|
|
|
# print(g - d)
|
|
|
|
# print(d - g)
|
|
|
|
#
|
|
|
|
# print()
|
2018-06-27 23:04:58 +02:00
|
|
|
# print(d + g)
|
2018-06-28 00:06:30 +02:00
|
|
|
# print(g + d)
|
|
|
|
#
|
|
|
|
# print()
|
|
|
|
# print(d * g)
|
|
|
|
# print(g * d)
|
2018-06-27 23:04:58 +02:00
|
|
|
# print(d)
|
|
|
|
# print(g)
|
2018-06-27 22:09:17 +02:00
|
|
|
# print(g - d)
|
|
|
|
# print(p / d)
|
|
|
|
# print(p.elements[0])
|
2018-06-27 19:14:55 +02:00
|
|
|
# a = PolyIntField(3, [1, 1, 2, 2])
|
2018-06-27 22:09:17 +02:00
|
|
|
# for e in a.elements:
|
|
|
|
# print(e.elements)
|
|
|
|
|
|
|
|
# print()
|
|
|
|
# print(a.elements[4])
|
|
|
|
# print(a.elements[8])
|
|
|
|
# print(a.elements[4] * a.elements[8])
|
|
|
|
# a.elements[3] / a.elements[1]
|