def poly_prime_gcd(f,g,p): """ Algorithm 2.2.1 (gcd for polynomials), p. 90 from Crandall and Pomerance, Prime Numbers, A Computational Perspective. For given polynomials f(x), g(x) in F[x], not both zero, this algorithm returns d(x) = gcd(f(x),g(x) """ # 1. [initialize] zero = poly1d([0]) if f.order < g.order or f == zero: f,g = g,f # 2. [Euclid loop] while g != zero: f,g = g, poly_prime_mod(f,g,p) # 3. [Make Monic] # take the leading coefficient. flc = f.c[0] # invert it. c = inverse(flc,p) # and multiply with f. return reduce_prime_poly(f*c,p)
def poly_prime_divmod(f,g,p): """ f and g are polynomials in F_p[x] return q,r such that f = q*g + r and r.order < g.order """ zero = poly1d([0]) x = poly1d([1,0]) d = f.order - g.order if d < 0: return zero, f if g == zero: raise ZeroDivisionError ("divmod(f,0) is undefined for all f") # this is a case which requires some thought. if f.order == 0: flc,glc = f.c[0],g.c[0] # get leading terms c = poly1d([inverse(glc,p)*flc % p]) c = reduce_prime_poly(c,p) return c,zero count = 0 while d >= 0 and f != zero: flc,glc = f.c[0],g.c[0] # get leading terms c = poly1d([inverse(glc,p)*flc % p]) term = c*(x**d) # term*g has same degree and same leading coefficient as f. # The following is calculated to reduce degree of f. f = f - term*g f = reduce_prime_poly(f,p) count += term d = f.order - g.order count = reduce_prime_poly(count,p) return count, f
def poly_prime_divmod(f, g, p): """ f and g are polynomials in F_p[x] return q,r such that f = q*g + r and r.order < g.order """ zero = poly1d([0]) x = poly1d([1, 0]) d = f.order - g.order if d < 0: return zero, f if g == zero: raise ZeroDivisionError("divmod(f,0) is undefined for all f") # this is a case which requires some thought. if f.order == 0: flc, glc = f.c[0], g.c[0] # get leading terms c = poly1d([inverse(glc, p) * flc % p]) c = reduce_prime_poly(c, p) return c, zero count = 0 while d >= 0 and f != zero: flc, glc = f.c[0], g.c[0] # get leading terms c = poly1d([inverse(glc, p) * flc % p]) term = c * (x**d) # term*g has same degree and same leading coefficient as f. # The following is calculated to reduce degree of f. f = f - term * g f = reduce_prime_poly(f, p) count += term d = f.order - g.order count = reduce_prime_poly(count, p) return count, f
def poly_gcd_extended(f,g,p): """ Algorithm 2.2.2 (Extended gcd for polynomials) p. 91 from Crandall and Pomerance, Prime Numbers, a Computational Perspective. Let F be a field. For given polynomials, f(x), g(x) in F[x], not both zero, with either deg f(x) >= deg g(x) or g(x) == 0, this algorithm returns (s(x),t(x),d(x)) in F[x] such that d = gcd (f,g) and sf + tg = d. (For ease of notation, we may drop the x argument). """ def rpp(f): return reduce_prime_poly(f,p) # 1. [initialize] zero = poly1d([0]) one = poly1d([1]) f = reduce_prime_poly(f,p) g = reduce_prime_poly(g,p) swap = False if f.order < g.order or f == zero: f,g = g,f swap = True s,t,d,u,v,w = one,zero,f,zero,one,g # 2. [Extended Euclid loop] while w != zero: q,r = poly_prime_divmod(d,w,p) s,t,d,u,v,w = u,v,w,rpp(s-q*u), rpp(t-q*v), r # 3. [Make Monic] # take the leading coefficient of d. # invert it. c = poly1d([inverse(d.c[0],p)]) if swap: s,t = t,s s,t,d = rpp(c*s), rpp(c*t), rpp(c*d) return s,t,d
def poly_gcd_extended(f, g, p): """ Algorithm 2.2.2 (Extended gcd for polynomials) p. 91 from Crandall and Pomerance, Prime Numbers, a Computational Perspective. Let F be a field. For given polynomials, f(x), g(x) in F[x], not both zero, with either deg f(x) >= deg g(x) or g(x) == 0, this algorithm returns (s(x),t(x),d(x)) in F[x] such that d = gcd (f,g) and sf + tg = d. (For ease of notation, we may drop the x argument). """ def rpp(f): return reduce_prime_poly(f, p) # 1. [initialize] zero = poly1d([0]) one = poly1d([1]) f = reduce_prime_poly(f, p) g = reduce_prime_poly(g, p) swap = False if f.order < g.order or f == zero: f, g = g, f swap = True s, t, d, u, v, w = one, zero, f, zero, one, g # 2. [Extended Euclid loop] while w != zero: q, r = poly_prime_divmod(d, w, p) s, t, d, u, v, w = u, v, w, rpp(s - q * u), rpp(t - q * v), r # 3. [Make Monic] # take the leading coefficient of d. # invert it. c = poly1d([inverse(d.c[0], p)]) if swap: s, t = t, s s, t, d = rpp(c * s), rpp(c * t), rpp(c * d) return s, t, d
def make_monic(f,p): if type(f) == int: f = poly1d([f]) f = reduce_prime_poly(f,p) r = deque(f.c.tolist()) # multiply each term by inverse of leading coefficient factor = inverse(f.c[0],p) l = [] while r: # take c off of the right c = r.popleft() # reduce it mod p and append it to the left. l.append(int(factor * c)%p) # return a monic poly return poly1d(l)