def zzx_hensel_lift(p, f, f_list, l): """Multifactor Hensel lifting. Given a prime p, polynomial f over Z[x] such that lc(f) is a unit modulo p, monic pair-wise coprime polynomials f_i over Z[x] satisfying: f = lc(f) f_1 ... f_r (mod p) and a positive integer l, returns a list of monic polynomials F_1, F_2, ..., F_r satisfying: f = lc(f) F_1 ... F_r (mod p**l) F_i = f_i (mod p), i = 1..r For more details on the implemented algorithm refer to: [1] J. von zur Gathen, J. Gerhard, Modern Computer Algebra, First Edition, Cambridge University Press, 1999, pp. 424 """ r = len(f_list) lc = zzx_LC(f) if r == 1: F = zzx_mul_term(f, igcdex(lc, p**l)[0], 0) return [zzx_trunc(F, p**l)] m = p k = int(r // 2) d = int(ceil(log(l, 2))) g = gf_from_int_poly([lc], p) for f_i in f_list[:k]: g = gf_mul(g, gf_from_int_poly(f_i, p), p) h = gf_from_int_poly(f_list[k], p) for f_i in f_list[k + 1:]: h = gf_mul(h, gf_from_int_poly(f_i, p), p) s, t, _ = gf_gcdex(g, h, p) g = gf_to_int_poly(g, p) h = gf_to_int_poly(h, p) s = gf_to_int_poly(s, p) t = gf_to_int_poly(t, p) for _ in range(1, d + 1): (g, h, s, t), m = zzx_hensel_step(m, f, g, h, s, t), m**2 return zzx_hensel_lift(p, g, f_list[:k], l) \ + zzx_hensel_lift(p, h, f_list[k:], l)
def zzx_hensel_lift(p, f, f_list, l): """Multifactor Hensel lifting. Given a prime p, polynomial f over Z[x] such that lc(f) is a unit modulo p, monic pair-wise coprime polynomials f_i over Z[x] satisfying: f = lc(f) f_1 ... f_r (mod p) and a positive integer l, returns a list of monic polynomials F_1, F_2, ..., F_r satisfying: f = lc(f) F_1 ... F_r (mod p**l) F_i = f_i (mod p), i = 1..r For more details on the implemented algorithm refer to: [1] J. von zur Gathen, J. Gerhard, Modern Computer Algebra, First Edition, Cambridge University Press, 1999, pp. 424 """ r = len(f_list) lc = zzx_LC(f) if r == 1: F = zzx_mul_term(f, igcdex(lc, p**l)[0], 0) return [ zzx_trunc(F, p**l) ] m = p k = int(r // 2) d = int(ceil(log(l, 2))) g = gf_from_int_poly([lc], p) for f_i in f_list[:k]: g = gf_mul(g, gf_from_int_poly(f_i, p), p) h = gf_from_int_poly(f_list[k], p) for f_i in f_list[k+1:]: h = gf_mul(h, gf_from_int_poly(f_i, p), p) s, t, _ = gf_gcdex(g, h, p) g = gf_to_int_poly(g, p) h = gf_to_int_poly(h, p) s = gf_to_int_poly(s, p) t = gf_to_int_poly(t, p) for _ in range(1, d+1): (g, h, s, t), m = zzx_hensel_step(m, f, g, h, s, t), m**2 return zzx_hensel_lift(p, g, f_list[:k], l) \ + zzx_hensel_lift(p, h, f_list[k:], l)
def test_gf_euclidean(): assert gf_gcd([], [], 11) == [] assert gf_gcd([2], [], 11) == [1] assert gf_gcd([], [2], 11) == [1] assert gf_gcd([2], [2], 11) == [1] assert gf_gcd([], [1,0], 11) == [1,0] assert gf_gcd([1,0], [], 11) == [1,0] assert gf_gcd([3,0], [3,0], 11) == [1,0] assert gf_gcd([1,8,7], [1,7,1,7], 11) == [1,7] assert gf_gcdex([], [], 11) == ([1], [], []) assert gf_gcdex([2], [], 11) == ([6], [], [1]) assert gf_gcdex([], [2], 11) == ([], [6], [1]) assert gf_gcdex([2], [2], 11) == ([], [6], [1]) assert gf_gcdex([], [3,0], 11) == ([], [4], [1,0]) assert gf_gcdex([3,0], [], 11) == ([4], [], [1,0]) assert gf_gcdex([3,0], [3,0], 11) == ([], [4], [1,0]) assert gf_gcdex([1,8,7], [1,7,1,7], 11) == ([5,6], [6], [1,7])