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_arith(): assert gf_neg([], 11) == [] assert gf_neg([1], 11) == [10] assert gf_neg([1,2,3], 11) == [10,9,8] assert gf_add_const([], 0, 11) == [] assert gf_sub_const([], 0, 11) == [] assert gf_add_const([], 3, 11) == [3] assert gf_sub_const([], 3, 11) == [8] assert gf_add_const([1], 3, 11) == [4] assert gf_sub_const([1], 3, 11) == [9] assert gf_add_const([8], 3, 11) == [] assert gf_sub_const([3], 3, 11) == [] assert gf_add_const([1,2,3], 3, 11) == [1,2,6] assert gf_sub_const([1,2,3], 3, 11) == [1,2,0] assert gf_mul_const([], 0, 11) == [] assert gf_mul_const([], 1, 11) == [] assert gf_mul_const([1], 0, 11) == [] assert gf_mul_const([1], 1, 11) == [1] assert gf_mul_const([1,2,3], 0, 11) == [] assert gf_mul_const([1,2,3], 1, 11) == [1,2,3] assert gf_mul_const([1,2,3], 7, 11) == [7,3,10] assert gf_add([], [], 11) == [] assert gf_add([1], [], 11) == [1] assert gf_add([], [1], 11) == [1] assert gf_add([1], [1], 11) == [2] assert gf_add([1], [2], 11) == [3] assert gf_add([1,2], [1], 11) == [1,3] assert gf_add([1], [1,2], 11) == [1,3] assert gf_add([1,2,3], [8,9,10], 11) == [9,0,2] assert gf_sub([], [], 11) == [] assert gf_sub([1], [], 11) == [1] assert gf_sub([], [1], 11) == [10] assert gf_sub([1], [1], 11) == [] assert gf_sub([1], [2], 11) == [10] assert gf_sub([1,2], [1], 11) == [1,1] assert gf_sub([1], [1,2], 11) == [10,10] assert gf_sub([3,2,1], [8,9,10], 11) == [6,4,2] assert gf_add_mul([1,5,6], [7,3], [8,0,6,1], 11) == [1,2,10,8,9] assert gf_sub_mul([1,5,6], [7,3], [8,0,6,1], 11) == [10,9,3,2,3] assert gf_mul([], [], 11) == [] assert gf_mul([], [1], 11) == [] assert gf_mul([1], [], 11) == [] assert gf_mul([1], [1], 11) == [1] assert gf_mul([5], [7], 11) == [2] assert gf_mul([3,0,0,6,1,2], [4,0,1,0], 11) == [1,0,3,2,4,3,1,2,0] assert gf_mul([4,0,1,0], [3,0,0,6,1,2], 11) == [1,0,3,2,4,3,1,2,0] assert gf_mul([2,0,0,1,7], [2,0,0,1,7], 11) == [4,0,0,4,6,0,1,3,5] assert gf_sqr([], 11) == [] assert gf_sqr([2], 11) == [4] assert gf_sqr([1,2], 11) == [1,4,4] assert gf_sqr([2,0,0,1,7], 11) == [4,0,0,4,6,0,1,3,5]