Rozwiązanie zadania "Ilorazy pierścienia wielomianów" #35
327
main.py
Normal file
327
main.py
Normal file
@ -0,0 +1,327 @@
|
||||
import itertools
|
||||
import ast
|
||||
import sys
|
||||
|
||||
|
||||
class Poly:
|
||||
|
||||
def __init__(self, int_mod, elements):
|
||||
self.elements = {}
|
||||
self.int_mod = int_mod
|
||||
|
||||
elements = [x % self.int_mod for x in elements]
|
||||
|
||||
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
|
||||
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(poly.int_mod, list(reversed(list(poly.elements.values()))))
|
||||
|
||||
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
|
||||
|
||||
els = {}
|
||||
|
||||
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)
|
||||
els[f"x{degree}"] = coefficient
|
||||
|
||||
mulpoly = divpoly * other
|
||||
|
||||
poly -= mulpoly
|
||||
|
||||
for i in poly.elements.keys():
|
||||
if poly.elements[f"{i}"] != 0:
|
||||
fdeg = int(i[1:])
|
||||
break
|
||||
|
||||
return Poly(poly.int_mod, list(reversed(list(els.values()))))
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.int_mod == other.int_mod and self.elements == other.elements
|
||||
|
||||
def __mod__(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
|
||||
|
||||
while fdeg >= sdeg:
|
||||
coefficient = other.elements[f"x{sdeg}"]
|
||||
|
||||
if poly.is_empty():
|
||||
break
|
||||
|
||||
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(poly.int_mod, list(reversed(list(poly.elements.values()))))
|
||||
|
||||
# TODO
|
||||
@staticmethod
|
||||
def gcd(self, other):
|
||||
|
||||
dividened = Poly(self.int_mod,
|
||||
list(reversed(list(self.elements.values()))))
|
||||
divisor = Poly(self.int_mod,
|
||||
list(reversed(list(other.elements.values()))))
|
||||
|
||||
if len(self.elements) < len(other.elements):
|
||||
dividened, divisor = divisor, dividened
|
||||
|
||||
# div_result = dividened % divisor
|
||||
|
||||
# if math.gcd(self.int_mod,
|
||||
# dividened.elements[f"x{len(dividened.elements) - 1}"]) == 1:
|
||||
# if dividened.elements[f"x{len(dividened.elements) - 1}"] == 1:
|
||||
# raise Exception("Leading dividened coefficient not invertible")
|
||||
div_result = dividened % divisor
|
||||
|
||||
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 div_result.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
|
||||
|
||||
return div_result
|
||||
|
||||
def is_empty(self):
|
||||
return self == Poly(self.int_mod, [0])
|
||||
|
||||
|
||||
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, self.int_modulo)],
|
||||
repeat=len(self.poly_modulo.elements) - 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))
|
||||
|
||||
# FIXME
|
||||
def invertibles(self):
|
||||
invertibles = []
|
||||
|
||||
one = Poly(self.int_modulo, [1])
|
||||
|
||||
for e in self.elements:
|
||||
for f in self.elements:
|
||||
if e * f % self.poly_modulo == one:
|
||||
invertibles.append(
|
||||
list(reversed(list(e.elements.values()))))
|
||||
break
|
||||
|
||||
return invertibles
|
||||
|
||||
def zero_divisors(self):
|
||||
zero_divisors = [[0]]
|
||||
|
||||
zero = Poly(self.int_modulo, [0])
|
||||
|
||||
for e in self.elements:
|
||||
for f in self.elements:
|
||||
if e * f % self.poly_modulo == zero and e != zero and f != zero:
|
||||
zero_divisors.append(
|
||||
list(reversed(list(e.elements.values()))))
|
||||
break
|
||||
|
||||
return zero_divisors
|
||||
|
||||
def nilpotents(self):
|
||||
nilpotents = []
|
||||
|
||||
zero = Poly(self.int_modulo, [0])
|
||||
|
||||
for e in self.elements:
|
||||
for n in range(1, self.int_modulo):
|
||||
if e ** n % self.poly_modulo == zero:
|
||||
nilpotents.append(list(reversed(list(e.elements.values()))))
|
||||
break
|
||||
|
||||
nilpotents[nilpotents.index([])] = [0]
|
||||
return nilpotents
|
||||
|
||||
def idempotents(self):
|
||||
idempotents = []
|
||||
|
||||
for e in self.elements:
|
||||
if e ** 2 % self.poly_modulo == e:
|
||||
idempotents.append(list(reversed(list(e.elements.values()))))
|
||||
|
||||
idempotents[idempotents.index([])] = [0]
|
||||
return idempotents
|
||||
|
||||
def __str__(self):
|
||||
str_form = "[\n\t"
|
||||
str_form += str(self.invertibles()) + ", # odwracalne\n\t"
|
||||
str_form += str(self.zero_divisors()) + ", # dzielniki zera\n\t"
|
||||
str_form += str(self.nilpotents()) + ", # nilpotenty\n\t"
|
||||
str_form += str(self.idempotents()) + " # idempotenty\n"
|
||||
str_form += "]\n"
|
||||
return str_form
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
print("Niepoprawny input")
|
||||
exit(1)
|
||||
|
||||
if sys.argv[1].find(",") != -1:
|
||||
print(f"Proszę użyć spacji, nie przecinków: '{sys.argv[1]}'")
|
||||
exit(1)
|
||||
|
||||
field = PolyIntField(int(sys.argv[1]), ast.literal_eval(sys.argv[2]))
|
||||
print(field)
|
Loading…
Reference in New Issue
Block a user