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