import itertools class Poly: def __init__(self, int_mod, elements): self.elements = {} self.int_mod = int_mod elements = list(reversed(elements)) z = 0 for i in elements: if i != 0: break z += 1 elements = elements[z:] i = len(elements) - 1 for e in elements: self.elements[f"x{i}"] = e % self.int_mod i -= 1 def __str__(self): 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 def __mul__(self, other): assert self.int_mod == other.int_mod 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: elements[degree] = coefficient % self.int_mod else: elements[degree] += coefficient % self.int_mod 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 __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): assert self.int_mod == other.int_mod elements = self.elements.copy() for f in other.elements: if f in elements: elements[f] += other.elements[f] else: elements[f] = other.elements[f] 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())))) def __truediv__(self, other): 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 # print(poly) # print(poly.elements) # print(fdeg) # print(sdeg) while fdeg >= sdeg: # coefficient = poly.elements[f"x{fdeg}"] / other.elements[f"x{sdeg}"] # coefficient %= poly.int_mod # coefficient = 0 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 # print(poly) poly -= mulpoly # print(poly) for i in poly.elements.keys(): if poly.elements[f"{i}"] != 0: fdeg = int(i[1:]) break return poly def __mod__(self, other): 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 els = [] for e in div_result.elements.keys(): if div_result.elements[e] != 0: els.append(div_result.elements[e]) div_result = Poly(self.int_mod, list(reversed(list(els)))) # # # # print(dividened) # # print(divisor) # # print(div_result) # # # print(div_result.elements) # dividened = Poly(dividened.int_mod, # list(reversed(list(divisor.elements.values())))) # divisor = Poly(divisor.int_mod, # list(reversed(list(div_result.elements.values())))) # print(dividened) # print(divisor) # div_result = dividened / divisor # # print() # print(dividened) # print(divisor) # print(div_result) # print() # while True: # 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 # # if div_result.is_empty(): # break # print(div_result) return div_result def is_empty(self): for e in self.elements: if self.elements[e] != 0: return False return True class PolyIntField: 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)) def get_nilpotents(self): nilpotents = [] # for element in self.elements: if __name__ == "__main__": # 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) # c = Poly(5, [4, 0, 0, 0, 1]) # d = Poly(5, [3, 1, 4, 0, 0, 0]) # print(c) # print(d) # print(c % d) # e = Poly(10, [-4, 0, -2, 1]) # f = Poly(10, [-3, 1]) # print(e / f) # print((a % b).elements) # d = Poly(10, [2, 0, 6, 0, 1]) # e = Poly(10, [5, 0, 1]) # print(d / e) # print(a - Poly(10, [0, 0, -3, 1])) # p = Poly(5, [-4, 0, -2, 1]) # print(p) # c = p * p # print(c.elements) # print(c) # print(p ** 2) # print(p) # print(d) # print(p) # print(p + d) # d = Poly(5, [-3, 1]) # g = Poly(5, [1, 2, 1]) # print(d) # print(g) # print() # # # print(g) # print(g - d) # print(d - g) # # print() # print(d + g) # print(g + d) # # print() # print(d * g) # print(g * d) # print(d) # print(g) # print(g - d) # print(p / d) # print(p.elements[0]) # a = PolyIntField(3, [1, 1, 2, 2]) # 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]