diff --git a/hw4.py b/hw4.py new file mode 100644 index 0000000..11758db --- /dev/null +++ b/hw4.py @@ -0,0 +1,84 @@ +from poly import Polynomial +from sys import argv +from ast import literal_eval +from fractions import gcd + +class QuotientRing(): + def __init__(self, f, m): + self.f = Polynomial(f, m) + self.m = m + self.remainders = self.remainders() + self.reversibles = self.reversibles() + self.zero_divisors = self.zero_divisors() + self.idempotent = self.idempotent() + self.nilpotent = self.nilpotent() + + def remainders(self): #n - exponent + rems = [] #lista reszt + m = self.m + t = [0] + i = 0 + while len(t) < len(self.f.poly): + rems.append(Polynomial(t, m)) + i = (i + 1) % m + t[0] = i + if i == 0: + if len(t) == 1: + t.append(1) + else: + t[1] += 1 + for j in range(1, len(t)): + if t[j] == 0 or t[j] % m != 0: + break + temp = t[j] % m + t[j] = 0 + if temp == 0: + if (j + 1) < len(t): + t[j+1] += 1 + else: + t.append(1) + return rems + + def reversibles(self): + return [ rem for rem in self.remainders if len(rem.poly_gcd(self.f).poly) == 1 ] + + #dopelnienie elementow odwracalnych + def zero_divisors(self): + return [ rem for rem in self.remainders if rem not in self.reversibles ] + + def idempotent(self): + idems = [] + for rem in self.remainders: + if (rem * rem / self.f) == (rem / self.f): + idems.append(rem) + try: + if idems[0].poly == []: #implementacja wielomianow ucina zera + idems[0].poly = [0] + except IndexError: + return idems + return idems + + def nilpotent(self): + nils = [] + phi = len([ i for i in range(1, self.m) if gcd(i, self.m) == 1 ]) + for zero_div in self.zero_divisors: + for i in range(self.m): + if len((zero_div ** i / self.f).poly) == 0: + nils.append(zero_div) + break + return nils + +def main(): + m = int(argv[1]) + f = literal_eval(argv[2]) + qr = QuotientRing(f, m) + out = [ + [ rev.poly for rev in qr.reversibles ], + [ zero_div.poly for zero_div in qr.zero_divisors ], + [ nil.poly for nil in qr.nilpotent ], + [ idem.poly for idem in qr.idempotent ] + ] + print(*out, sep='\n') + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/poly.py b/poly.py new file mode 100644 index 0000000..28473bd --- /dev/null +++ b/poly.py @@ -0,0 +1,115 @@ +from fractions import gcd +class Polynomial(): + def __init__(self, lst, mod): + self.poly = list(map(lambda x: x % mod, lst)) + self.mod = mod + self.normalize() + def normalize(self): + while self.poly and self.poly[-1] == 0: + self.poly.pop() + + #zwraca jednomian stopnia n + @staticmethod + def Monomial(n, c, mod): + zeros = [0]*n + + zeros.append(c) + return Polynomial(zeros, mod) + + def __add__(self, p2): + p1 = self + len_p1, len_p2= len(p1.poly), len(p2.poly) + res = [0] * max(len_p1, len_p2) + if len_p1 > len_p2: + for _ in range(len_p1-len_p2): + p2.poly.append(0) + else: + for _ in range(len_p2-len_p1): + p1.poly.append(0) + + for i in range(len(res)): + res[i] = (p1.poly[i] + p2.poly[i]) % self.mod + return Polynomial(res, self.mod) + + def __sub__(self, p2): + p1 = self + res = [] + len_p2 = len(p2.poly) + for i in range(len(p1.poly)): + if i < len_p2: + res.append(p1.poly[i] - p2.poly[i] % self.mod) + else: + res.append(p1.poly[i]) + return Polynomial(res, self.mod) + + def __mul__(self, p2): + res = [0]*(len(self.poly)+len(p2.poly)-1) + for i, x1 in enumerate(self.poly): + for j, x2 in enumerate(p2.poly): + res[i+j] += x1 * x2 % self.mod + return Polynomial(res, self.mod) + + def __eq__(self, p2): + p1 = self + return p1.poly == p2.poly and p1.mod == p2.mod + + def __pow__(self, n): + p1 = self + for i in range(n): + p1 = p1 * p1 + return p1 + + def __truediv__(self, p2): + p1 = self + m = self.mod + + if len(p1.poly) < len(p2.poly): + return p1 + + if len(p2.poly) == 0: + raise ZeroDivisionError + + divisor_coeff = p2.poly[-1] + divisor_exp = len(p2.poly) - 1 + while len(p1.poly) >= len(p2.poly): + max_coeff_p1 = p1.poly[-1] #wspolczynnik przy najwyzszej potedze + try: + tmp_coeff = modDiv(max_coeff_p1, divisor_coeff, m) + except ZeroDivisionError as e: + raise e + + tmp_exp = len(p1.poly)-1 - divisor_exp + tmp = [0] * tmp_exp + tmp.append(tmp_coeff) + sub = Polynomial(tmp, m) * p2 + p1 = p1 - sub + p1.normalize() + return Polynomial(p1.poly, m) + + def poly_gcd(self, p2): + p1 = self + try: + divisible = p2 + except ZeroDivisionError as e: + raise e + if p2.poly == []: + return p1 + + return p2.poly_gcd(p1 / p2) + +def modDiv(a, b, m): # a*b^-1 (mod m) + if gcd(b, m) != 1: + raise ZeroDivisionError + else: + return (a * modinv(b, m)) % m +#rozszerzony algorytm euklidesa +def egcd(a, b): + if a == 0: + return (b, 0, 1) + else: + g, y, x = egcd(b % a, a) + return (g, x - (b // a) * y, y) + +def modinv(a, m): + g, x, y = egcd(a, m) + return x % m \ No newline at end of file