Rozwiązanie zadania "Ilorazy pierścienia wielomianów" #35

Closed
s426211 wants to merge 15 commits from (deleted):zad4 into master

327
main.py Normal file
View 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)