(p, f, f_list, l, K)
return dup_zz_hensel_lift(p, g, f_list[:k], l, K) \
        + dup_zz_hensel_lift(p, h, f_list[k:], l, K)
Multifactor Hensel lifting in `Z[x]`.

    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

    References
    ==========

    1. [Gathen99]_
Multifactor Hensel lifting in `Z[x]`.
Multifactor Hensel lifting in Z [ x ] .
def dup_zz_hensel_lift(p, f, f_list, l, K):
    """
    Multifactor Hensel lifting in `Z[x]`.

    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

    References
    ==========

    1. [Gathen99]_

    """
    r = len(f_list)
    lc = dup_LC(f, K)

    if r == 1:
        F = dup_mul_ground(f, K.gcdex(lc, p**l)[0], K)
        return [ dup_trunc(F, p**l, K) ]

    m = p
    k = 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, K)

    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, K)

    s, t, _ = gf_gcdex(g, h, p, K)

    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 = dup_zz_hensel_step(m, f, g, h, s, t, K), m**2

    return dup_zz_hensel_lift(p, g, f_list[:k], l, K) \
        + dup_zz_hensel_lift(p, h, f_list[k:], l, K)
def dup_zz_hensel_lift ( p , f , f_list , l , K ) : r = len ( f_list ) lc = dup_LC ( f , K ) if r == 1 : F = dup_mul_ground ( f , K . gcdex ( lc , p ** l ) [ 0 ] , K ) return [ dup_trunc ( F , p ** l , K ) ] m = p k = 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 , K ) 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 , K ) s , t , _ = gf_gcdex ( g , h , p , K ) 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 = dup_zz_hensel_step ( m , f , g , h , s , t , K ) , m ** 2 return dup_zz_hensel_lift ( p , g , f_list [ : k ] , l , K ) + dup_zz_hensel_lift ( p , h , f_list [ k : ] , l , K )