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 } }
def gcd_small_primes(f, g): """Modular small primes version for primitive polynomials.""" if f.degree < g.degree: f, g = g, f if not g: return f if g.degree == 0: c = reduce(modint.gcd, f.coeffs.itervalues(), g[0]) return IntPoly({0: c}) n = f.degree A = max([abs(c) for c in f.coeffs.itervalues()] + [abs(c) for c in g.coeffs.itervalues()]) b = modint.gcd(f[f.degree], g[g.degree]) B = int(math.ceil(2**n*A*b*math.sqrt(n+1))) k = int(math.ceil(2*math.log((n+1)**n*b*A**(2*n), 2))) l = int(math.ceil(math.log(2*B + 1, 2))) # TODO: the minimum is needed for very small polynomials? prime_border = max(int(math.ceil(2*k*math.log(k))), 51) while True: while True: # Choose primes. S = [] while len(S) < l: p = ntheory.generate.randprime(2, prime_border + 1) if (p not in S) and (b % p): # p doesn't divide b. S.append(p) # Call the modular gcd. v, ff, gg = {}, {}, {} for p in S: poly_type = gfpoly.GFPolyFactory(p) ff[p] = poly_type.from_int_dict(f.coeffs) gg[p] = poly_type.from_int_dict(g.coeffs) v[p] = gfpoly.gcd(ff[p], gg[p]) e = min([v[p].degree for p in S]) unlucky = [] for p in S: if v[p].degree != e: unlucky.append(p) S.remove(p) del v[p] del ff[p] del gg[p] if len(S) < l/2: # Forget all primes. continue # Replace the unlucky primes. while len(S) < l: p = ntheory.generate.randprime(2, prime_border) if (p in unlucky) or (p in S) or (b % p == 0): continue poly_type = gfpoly.GFPolyFactory(p) ff[p] = poly_type.from_int_dict(f.coeffs) gg[p] = poly_type.from_int_dict(g.coeffs) v[p] = gfpoly.gcd(ff[p], gg[p]) if v[p].degree == e: S.append(p) else: unlucky.append(p) del v[p] del ff[p] del gg[p] break # The primes are good. fff, ggg = {}, {} for p in S: fff[p], r = gfpoly.div(ff[p], v[p]) assert not r ggg[p], r = gfpoly.div(gg[p], v[p]) assert not r w_dict, fff_dict, ggg_dict = {}, {}, {} crt_mm, crt_e, crt_s = modint.crt1(S) for i in xrange(0, e+1): C = [int(v[p][i]*v[p].__class__.coeff_type(b)) for p in S] c = modint.crt2(S, C, crt_mm, crt_e, crt_s, True) if c: w_dict[i] = c for i in xrange(0, f.degree - e + 1): c = modint.crt2(S, [int(fff[p][i]) for p in S], crt_mm, crt_e, crt_s, True) if c: fff_dict[i] = c for i in xrange(0, g.degree - e + 1): c = modint.crt2(S, [int(ggg[p][i]) for p in S], crt_mm, crt_e, crt_s, True) if c: ggg_dict[i] = c w_norm = sum([abs(c) for c in w_dict.itervalues()]) fff_norm = sum([abs(c) for c in fff_dict.itervalues()]) ggg_norm = sum([abs(c) for c in ggg_dict.itervalues()]) if w_norm*fff_norm <= B and w_norm*ggg_norm <= B: break content, result = IntPoly(w_dict).primitive() return result