def mcrt(m, v, r, symmetric=False): assert crt(m, v, symmetric)[0] == r mm, e, s = crt1(m) assert crt2(m, v, mm, e, s, symmetric) == (r, mm)
def zzx_mod_gcd(f, g, **flags): """Modular small primes polynomial GCD over Z[x]. Given univariate polynomials f and g over Z[x], returns their GCD and cofactors, i.e. polynomials h, cff and cfg such that: h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h) The algorithm uses modular small primes approach. It works by computing several GF(p)[x] GCDs for a set of randomly chosen primes and uses Chinese Remainder Theorem to recover the GCD over Z[x] from its images. The algorithm is probabilistic which means it never fails, however its running time depends on the number of unlucky primes chosen for computing GF(p)[x] images. 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. 158 """ n = zzx_degree(f) m = zzx_degree(g) cf = zzx_content(f) cg = zzx_content(g) h = igcd(cf, cg) f = [c // h for c in f] g = [c // h for c in g] if n <= 0 or m <= 0: return zzx_strip([h]), f, g else: gcd = h A = max(zzx_abs(f) + zzx_abs(g)) b = igcd(zzx_LC(f), zzx_LC(g)) B = int(ceil(2**n * A * b * sqrt(n + 1))) k = int(ceil(2 * b * log((n + 1)**n * A**(2 * n), 2))) l = int(ceil(log(2 * B + 1, 2))) prime_max = max(int(ceil(2 * k * log(k))), 51) while True: while True: primes = set([]) unlucky = set([]) ff, gg, hh = {}, {}, {} while len(primes) < l: p = randprime(3, prime_max + 1) if (p in primes) and (b % p == 0): continue F = gf_from_int_poly(f, p) G = gf_from_int_poly(g, p) H = gf_gcd(F, G, p) primes.add(p) ff[p] = F gg[p] = G hh[p] = H e = min([gf_degree(h) for h in hh.itervalues()]) for p in set(primes): if gf_degree(hh[p]) != e: primes.remove(p) unlucky.add(p) del ff[p] del gg[p] del hh[p] if len(primes) < l // 2: continue while len(primes) < l: p = randprime(3, prime_max + 1) if (p in primes) or (p in unlucky) or (b % p == 0): continue F = gf_from_int_poly(f, p) G = gf_from_int_poly(g, p) H = gf_gcd(F, G, p) if gf_degree(H) != e: unlucky.add(p) else: primes.add(p) ff[p] = F gg[p] = G hh[p] = H break fff, ggg = {}, {} for p in primes: fff[p] = gf_quo(ff[p], hh[p], p) ggg[p] = gf_quo(gg[p], hh[p], p) F, G, H = [], [], [] crt_mm, crt_e, crt_s = crt1(primes) for i in xrange(0, e + 1): C = [b * zzx_nth(hh[p], i) for p in primes] c = crt2(primes, C, crt_mm, crt_e, crt_s, True) H.insert(0, c) H = zzx_strip(H) for i in xrange(0, zzx_degree(f) - e + 1): C = [zzx_nth(fff[p], i) for p in primes] c = crt2(primes, C, crt_mm, crt_e, crt_s, True) F.insert(0, c) for i in xrange(0, zzx_degree(g) - e + 1): C = [zzx_nth(ggg[p], i) for p in primes] c = crt2(primes, C, crt_mm, crt_e, crt_s, True) G.insert(0, c) H_norm = zzx_l1_norm(H) F_norm = zzx_l1_norm(F) G_norm = zzx_l1_norm(G) if H_norm * F_norm <= B and H_norm * G_norm <= B: break return zzx_mul_term(H, gcd, 0), F, G
def zzx_mod_gcd(f, g, **flags): """Modular small primes polynomial GCD over Z[x]. Given univariate polynomials f and g over Z[x], returns their GCD and cofactors, i.e. polynomials h, cff and cfg such that: h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h) The algorithm uses modular small primes approach. It works by computing several GF(p)[x] GCDs for a set of randomly chosen primes and uses Chinese Remainder Theorem to recover the GCD over Z[x] from its images. The algorithm is probabilistic which means it never fails, however its running time depends on the number of unlucky primes chosen for computing GF(p)[x] images. 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. 158 """ n = zzx_degree(f) m = zzx_degree(g) cf = zzx_content(f) cg = zzx_content(g) h = igcd(cf, cg) f = [ c // h for c in f ] g = [ c // h for c in g ] if n <= 0 or m <= 0: return zzx_strip([h]), f, g else: gcd = h A = max(zzx_abs(f) + zzx_abs(g)) b = igcd(zzx_LC(f), zzx_LC(g)) B = int(ceil(2**n*A*b*sqrt(n + 1))) k = int(ceil(2*b*log((n + 1)**n*A**(2*n), 2))) l = int(ceil(log(2*B + 1, 2))) prime_max = max(int(ceil(2*k*log(k))), 51) while True: while True: primes = set([]) unlucky = set([]) ff, gg, hh = {}, {}, {} while len(primes) < l: p = randprime(3, prime_max+1) if (p in primes) and (b % p == 0): continue F = gf_from_int_poly(f, p) G = gf_from_int_poly(g, p) H = gf_gcd(F, G, p) primes.add(p) ff[p] = F gg[p] = G hh[p] = H e = min([ gf_degree(h) for h in hh.itervalues() ]) for p in set(primes): if gf_degree(hh[p]) != e: primes.remove(p) unlucky.add(p) del ff[p] del gg[p] del hh[p] if len(primes) < l // 2: continue while len(primes) < l: p = randprime(3, prime_max+1) if (p in primes) or (p in unlucky) or (b % p == 0): continue F = gf_from_int_poly(f, p) G = gf_from_int_poly(g, p) H = gf_gcd(F, G, p) if gf_degree(H) != e: unlucky.add(p) else: primes.add(p) ff[p] = F gg[p] = G hh[p] = H break fff, ggg = {}, {} for p in primes: fff[p] = gf_quo(ff[p], hh[p], p) ggg[p] = gf_quo(gg[p], hh[p], p) F, G, H = [], [], [] crt_mm, crt_e, crt_s = crt1(primes) for i in xrange(0, e + 1): C = [ b * zzx_nth(hh[p], i) for p in primes ] c = crt2(primes, C, crt_mm, crt_e, crt_s, True) H.insert(0, c) H = zzx_strip(H) for i in xrange(0, zzx_degree(f) - e + 1): C = [ zzx_nth(fff[p], i) for p in primes ] c = crt2(primes, C, crt_mm, crt_e, crt_s, True) F.insert(0, c) for i in xrange(0, zzx_degree(g) - e + 1): C = [ zzx_nth(ggg[p], i) for p in primes ] c = crt2(primes, C, crt_mm, crt_e, crt_s, True) G.insert(0, c) H_norm = zzx_l1_norm(H) F_norm = zzx_l1_norm(F) G_norm = zzx_l1_norm(G) if H_norm*F_norm <= B and H_norm*G_norm <= B: break return zzx_mul_term(H, gcd, 0), F, G