Example #1
0
def multi_hensel_lift(p, f, f_list, l):
    """Multifactor Hensel lifting.

    Input: an integer p, an univariate integer polynomial f such that
    f's leading coefficient lc(f) is a unit mod p. Monic polynomials
    f_i that are pair-wise coprime mod p satisfying
        f = lc(f)*f_1*...*f_r mod p
    and an integer l.

    Output: monic polynomials ff_1, ..., ff_r satisfying
        f = lc(f)*ff_1*...*ff_r mod p**l
        ff_i = f_i mod p

    """
    r = len(f_list)
    lc = f[f.degree]

    if r == 1:
        lc_g, lc_s, lc_t = modint.xgcd(lc, p**l)
        return [f.scale(lc_s).mod_int(p**l, symmetric=True)]
    k = int(r/2)
    d = int(math.ceil(math.log(l, 2)))

    # Divide and conquer the factors. 
    IntModpPoly = gfpoly.GFPolyFactory(p)
    g = IntModpPoly.from_int_dict({0:lc})
    for f_i in f_list[0:k]:
        g *= IntModpPoly.from_int_dict(f_i.coeffs)
    h = IntModpPoly.from_int_dict(f_list[k].coeffs)
    for f_i in f_list[k+1:]:
        h *= IntModpPoly.from_int_dict(f_i.coeffs)
    x, s, t = gfpoly.xgcd(g, h)
    g = IntPoly(g.to_sym_int_dict())
    h = IntPoly(h.to_sym_int_dict())
    s = IntPoly(s.to_sym_int_dict())
    t = IntPoly(t.to_sym_int_dict())

    # Lift the two coprime parts.
    m = p
    for j in range(1, d+1):
        g, h, s, t = hensel_step(m, f, g, h, s, t)
        m *= m

    # Call recursively.
    return multi_hensel_lift(p, g, f_list[0:k], l) \
           + multi_hensel_lift(p, h, f_list[k:], l)
def test_GFPoly():
    from sympy.polynomials.fast import gfpoly

    p = 5
    IntMod5Poly = gfpoly.GFPolyFactory(p)
    IntMod5 = IntMod5Poly.coeff_type

    f = IntMod5Poly.from_int_dict({2: 1, 0: 1})
    g = IntMod5Poly.from_int_dict({3: 2, 1: 1, 0: 2})

    assert f[0] == IntMod5(1)
    assert f[1] == IntMod5(0)

    assert +f == f
    assert -f == IntMod5Poly.from_int_dict({2: -1, 0: -1})
    assert f.scale(IntMod5(2), 3) == IntMod5Poly.from_int_dict({5: 2, 3: 2})
    assert f + g == IntMod5Poly.from_int_dict({3: 2, 2: 1, 1: 1, 0: 3})
    assert f - g == IntMod5Poly.from_int_dict({3: -2, 2: 1, 1: -1, 0: -1})
    assert f * g == IntMod5Poly.from_int_dict({5: 2, 3: 3, 2: 2, 1: 1, 0: 2})
    assert f**5 == IntMod5Poly.from_int_dict({10: 1, 0: 1})
    assert (f * g).diff() == IntMod5Poly.from_int_dict({2: 4, 1: 4, 0: 1})

    assert g.monic() \
           == (IntMod5(2), IntMod5Poly.from_int_dict({3:1, 1:-2, 0:1}))
    assert g.monic()[1].to_sym_int_dict() == {3: 1, 1: -2, 0: 1}

    q, r = gfpoly.div(f, g)
    assert (not q) and (r == f)
    q, r = gfpoly.div(g, f)
    assert q == IntMod5Poly.from_int_dict({1: 2})
    assert r == IntMod5Poly.from_int_dict({1: 4, 0: 2})

    assert gfpoly.gcd(f, g) == IntMod5Poly.from_int_dict({1: 1, 0: 3})
    assert gfpoly.gcd(f**3, f**4) == f**3

    h, s, t = gfpoly.xgcd(f, g)
    assert h == IntMod5Poly.from_int_dict({1: 1, 0: 3})
    assert s == IntMod5Poly.from_int_dict({1: 2})
    assert t == IntMod5Poly.from_int_dict({0: 4})
    assert h == (s * f + t * g)

    assert gfpoly.truncate(f, 5) == f
    assert gfpoly.truncate(f, 1) == IntMod5Poly.from_int_dict({0: 1})

    assert gfpoly.pow_mod(f, 3, IntMod5Poly.from_int_dict({2:1})) \
           == gfpoly.truncate(f**3, 2)

    p = 3
    IntMod3Poly = gfpoly.GFPolyFactory(p)
    f = IntMod3Poly.from_int_dict({1:1}) \
        * IntMod3Poly.from_int_dict({1:1, 0:1}) \
        * IntMod3Poly.from_int_dict({2:1, 0:1}) \
        * IntMod3Poly.from_int_dict({2:1, 1:1, 0:2})
    a = gfpoly.distinct_degree_factor(f)
    assert [g.to_sym_int_dict() for g in a] \
           == [{1: 1, 2: 1}, {0: -1, 1: 1, 3: 1, 4: 1}]
    b = gfpoly.equal_degree_factor(a[0], 1)
    assert sorted([g.to_sym_int_dict() for g in b]) \
           == sorted([{1:1}, {1:1, 0:1}])
    c = gfpoly.equal_degree_factor(a[1], 2)
    assert sorted([g.to_sym_int_dict() for g in c]) \
           == sorted([{2:1, 0:1}, {2:1, 1:1, 0:-1}])

    r = gfpoly.factor_sqf(f)
    assert r[0] == IntMod3Poly.coeff_type(1)
    r = r[1:]
    assert len(r) == 4
    assert IntMod3Poly.from_int_dict({1: 1}) in r
    assert IntMod3Poly.from_int_dict({1: 1, 0: 1}) in r
    assert IntMod3Poly.from_int_dict({2: 1, 0: 1}) in r
    assert IntMod3Poly.from_int_dict({2: 1, 1: 1, 0: 2}) in r

    f = IntMod3Poly.from_int_dict({1:1}) \
    * IntMod3Poly.from_int_dict({1:1, 0:1}) \
    * IntMod3Poly.from_int_dict({1:1, 0:1}) \
    * IntMod3Poly.from_int_dict({2:1, 0:1}) \
    * IntMod3Poly.from_int_dict({2:1, 1:1, 0:2}) \
    * IntMod3Poly.from_int_dict({2:1, 1:1, 0:2}) \
    * IntMod3Poly.from_int_dict({1:1, 0:1}) \
    * IntMod3Poly.from_int_dict({1:1, 0:1}) \
    * IntMod3Poly.from_int_dict({2:1, 0:1}) \
    * IntMod3Poly.from_int_dict({2:1, 1:1, 0:2}) \
    * IntMod3Poly.from_int_dict({2:1, 1:1, 0:2}) \
    * IntMod3Poly.from_int_dict({1:1, 0:1}) \
    * IntMod3Poly.from_int_dict({1:1, 0:1}) \
    * IntMod3Poly.from_int_dict({2:1, 0:1}) \
    * IntMod3Poly.from_int_dict({2:1, 1:1, 0:2}) \
    * IntMod3Poly.from_int_dict({2:1, 1:1, 0:2}) \
    * IntMod3Poly.from_int_dict({2:1, 1:1, 0:2})
    r = gfpoly.factor(f)
    assert r[0] == IntMod3Poly.coeff_type(1)
    test_dict = {}
    for item in r[1:]:
        test_dict[item[1]] = item[0].to_sym_int_dict()
    assert test_dict == {
        1: {
            1: 1
        },
        3: {
            2: 1,
            0: 1
        },
        6: {
            1: 1,
            0: 1
        },
        7: {
            2: 1,
            1: 1,
            0: -1
        }
    }