def test_zzx_hensel_lift(): f = zzx_from_dict({4:1, 0:-1}) f1 = zzx_from_dict({1:1, 0:-1}) f2 = zzx_from_dict({1:1, 0:-2}) f3 = zzx_from_dict({1:1, 0: 2}) f4 = zzx_from_dict({1:1, 0: 1}) ff_list = zzx_hensel_lift(5, f, [f1, f2, f3, f4], 4) assert zzx_to_dict(ff_list[0]) == {0: -1, 1: 1} assert zzx_to_dict(ff_list[1]) == {0: -182, 1: 1} assert zzx_to_dict(ff_list[2]) == {0: 182, 1: 1} assert zzx_to_dict(ff_list[3]) == {0: 1, 1: 1}
def test_zzx_from_to(): assert zzx_from_dict({}) == [] f = [3, 0, 0, 2, 0, 0, 0, 0, 8] g = {8: 3, 5: 2, 0: 8} assert zzx_from_dict(g) == f assert zzx_to_dict(f) == g g = (3 * x**8 + 2 * x**5 + 8).as_poly(x) assert zzx_from_poly(g) == f assert zzx_to_poly(f, x) == g
def test_zzx_reduce(): assert zzx_reduce([]) == (1, []) assert zzx_reduce([2]) == (1, [2]) assert zzx_reduce([1, 2, 3]) == (1, [1, 2, 3]) assert zzx_reduce([1, 0, 2, 0, 3]) == (2, [1, 2, 3]) assert zzx_reduce([1, 0, 2, 0, 3]) == (2, [1, 2, 3]) assert zzx_reduce(zzx_from_dict({7:1,1:1})) == \ (1, [1, 0, 0, 0, 0, 0, 1, 0]) assert zzx_reduce(zzx_from_dict({7:1,0:1})) == \ (7, [1, 1]) assert zzx_reduce(zzx_from_dict({7:1,3:1})) == \ (1, [1, 0, 0, 0, 1, 0, 0, 0]) assert zzx_reduce(zzx_from_dict({7:1,4:1})) == \ (1, [1, 0, 0, 1, 0, 0, 0, 0]) assert zzx_reduce(zzx_from_dict({8:1,4:1})) == \ (4, [1, 1, 0]) assert zzx_reduce(zzx_from_dict({8:1})) == \ (8, [1, 0]) assert zzx_reduce(zzx_from_dict({7:1})) == \ (7, [1, 0]) assert zzx_reduce(zzx_from_dict({1:1})) == \ (1, [1, 0])
def test_zzx_from_to(): assert zzx_from_dict({}) == [] f = [3,0,0,2,0,0,0,0,8] g = {8: 3, 5: 2, 0: 8} assert zzx_from_dict(g) == f assert zzx_to_dict(f) == g g = (3*x**8 + 2*x**5 + 8).as_poly(x) assert zzx_from_poly(g) == f assert zzx_to_poly(f, x) == g
def test_zzx_hensel_lift(): f = zzx_from_dict({4: 1, 0: -1}) f1 = zzx_from_dict({1: 1, 0: -1}) f2 = zzx_from_dict({1: 1, 0: -2}) f3 = zzx_from_dict({1: 1, 0: 2}) f4 = zzx_from_dict({1: 1, 0: 1}) ff_list = zzx_hensel_lift(5, f, [f1, f2, f3, f4], 4) assert zzx_to_dict(ff_list[0]) == {0: -1, 1: 1} assert zzx_to_dict(ff_list[1]) == {0: -182, 1: 1} assert zzx_to_dict(ff_list[2]) == {0: 182, 1: 1} assert zzx_to_dict(ff_list[3]) == {0: 1, 1: 1}
def test_zzx_reduce(): assert zzx_reduce([]) == (1, []) assert zzx_reduce([2]) == (1, [2]) assert zzx_reduce([1,2,3]) == (1, [1,2,3]) assert zzx_reduce([1,0,2,0,3]) == (2, [1,2,3]) assert zzx_reduce([1,0,2,0,3]) == (2, [1,2,3]) assert zzx_reduce(zzx_from_dict({7:1,1:1})) == \ (1, [1, 0, 0, 0, 0, 0, 1, 0]) assert zzx_reduce(zzx_from_dict({7:1,0:1})) == \ (7, [1, 1]) assert zzx_reduce(zzx_from_dict({7:1,3:1})) == \ (1, [1, 0, 0, 0, 1, 0, 0, 0]) assert zzx_reduce(zzx_from_dict({7:1,4:1})) == \ (1, [1, 0, 0, 1, 0, 0, 0, 0]) assert zzx_reduce(zzx_from_dict({8:1,4:1})) == \ (4, [1, 1, 0]) assert zzx_reduce(zzx_from_dict({8:1})) == \ (8, [1, 0]) assert zzx_reduce(zzx_from_dict({7:1})) == \ (7, [1, 0]) assert zzx_reduce(zzx_from_dict({1:1})) == \ (1, [1, 0])
def test_zzx_factor(): f = [1, 0, 0, 1, 1] for i in xrange(0, 20): assert zzx_factor(f) == (1, [(f, 1)]) assert zzx_factor([2,4,2]) == \ (2, [([1, 1], 2)]) assert zzx_factor([1,-6,11,-6]) == \ (1, [([1,-3], 1), ([1,-2], 1), ([1,-1], 1)]) assert zzx_factor([-1,0,0,0,1,0,0]) == \ (-1, [([1,-1], 1), ([1, 1], 1), ([1, 0], 2), ([1, 0, 1], 1)]) assert zzx_factor(zzx_from_dict({10:1, 0:-1})) == \ (1, [([1,-1], 1), ([1, 1], 1), ([1,-1, 1,-1, 1], 1), ([1, 1, 1, 1, 1], 1)])
def test_zzx_factor(): f = [1,0,0,1,1] for i in xrange(0, 20): assert zzx_factor(f) == (1, [(f, 1)]) assert zzx_factor([2,4,2]) == \ (2, [([1, 1], 2)]) assert zzx_factor([1,-6,11,-6]) == \ (1, [([1,-3], 1), ([1,-2], 1), ([1,-1], 1)]) assert zzx_factor([-1,0,0,0,1,0,0]) == \ (-1, [([1,-1], 1), ([1, 1], 1), ([1, 0], 2), ([1, 0, 1], 1)]) assert zzx_factor(zzx_from_dict({10:1, 0:-1})) == \ (1, [([1,-1], 1), ([1, 1], 1), ([1,-1, 1,-1, 1], 1), ([1, 1, 1, 1, 1], 1)])
def test_zzx_hensel_step(): f = zzx_from_dict({4: 1, 0: -1}) g = zzx_from_dict({3: 1, 2: 2, 1: -1, 0: -2}) h = zzx_from_dict({1: 1, 0: -2}) s = zzx_from_dict({0: -2}) t = zzx_from_dict({2: 2, 1: -2, 0: -1}) G, H, S, T = zzx_hensel_step(5, f, g, h, s, t) assert G == zzx_from_dict({3: 1, 2: 7, 1: -1, 0: -7}) assert H == zzx_from_dict({1: 1, 0: -7}) assert S == zzx_from_dict({0: 8}) assert T == zzx_from_dict({2: -8, 1: -12, 0: -1})
def test_zzx_hensel_step(): f = zzx_from_dict({4:1, 0:-1}) g = zzx_from_dict({3:1, 2:2, 1:-1, 0:-2}) h = zzx_from_dict({1:1, 0:-2}) s = zzx_from_dict({0:-2}) t = zzx_from_dict({2:2, 1:-2, 0:-1}) G, H, S, T = zzx_hensel_step(5, f, g, h, s, t) assert G == zzx_from_dict({3:1, 2:7, 1:-1, 0:-7}) assert H == zzx_from_dict({1:1, 0:-7}) assert S == zzx_from_dict({0:8}) assert T == zzx_from_dict({2:-8, 1:-12, 0:-1})
def test_zzx_cyclotomic_factor(): assert zzx_cyclotomic_factor([]) is None assert zzx_cyclotomic_factor([1]) is None f = zzx_from_dict({10:2, 0:-1}) assert zzx_cyclotomic_factor(f) is None f = zzx_from_dict({10:1, 0:-3}) assert zzx_cyclotomic_factor(f) is None f = zzx_from_dict({10:1, 5:1, 0:-1}) assert zzx_cyclotomic_factor(f) is None f = zzx_from_dict({1:1,0:1}) assert zzx_cyclotomic_factor(f) == \ [[1, 1]] f = zzx_from_dict({1:1,0:-1}) assert zzx_cyclotomic_factor(f) == \ [[1, -1]] f = zzx_from_dict({2:1,0:1}) assert zzx_cyclotomic_factor(f) == \ [[1, 0, 1]] f = zzx_from_dict({2:1,0:-1}) assert zzx_cyclotomic_factor(f) == \ [[1,-1], [1, 1]] f = zzx_from_dict({27:1,0:1}) assert zzx_cyclotomic_factor(f) == \ [[1, 1], [1, -1, 1], [1, 0, 0, -1, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1]] f = zzx_from_dict({27:1,0:-1}) assert zzx_cyclotomic_factor(f) == \ [[1, -1], [1, 1, 1], [1, 0, 0, 1, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1]]
def test_zzx_cyclotomic_factor(): assert zzx_cyclotomic_factor([]) is None assert zzx_cyclotomic_factor([1]) is None f = zzx_from_dict({10: 2, 0: -1}) assert zzx_cyclotomic_factor(f) is None f = zzx_from_dict({10: 1, 0: -3}) assert zzx_cyclotomic_factor(f) is None f = zzx_from_dict({10: 1, 5: 1, 0: -1}) assert zzx_cyclotomic_factor(f) is None f = zzx_from_dict({1: 1, 0: 1}) assert zzx_cyclotomic_factor(f) == \ [[1, 1]] f = zzx_from_dict({1: 1, 0: -1}) assert zzx_cyclotomic_factor(f) == \ [[1, -1]] f = zzx_from_dict({2: 1, 0: 1}) assert zzx_cyclotomic_factor(f) == \ [[1, 0, 1]] f = zzx_from_dict({2: 1, 0: -1}) assert zzx_cyclotomic_factor(f) == \ [[1,-1], [1, 1]] f = zzx_from_dict({27: 1, 0: 1}) assert zzx_cyclotomic_factor(f) == \ [[1, 1], [1, -1, 1], [1, 0, 0, -1, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1]] f = zzx_from_dict({27: 1, 0: -1}) assert zzx_cyclotomic_factor(f) == \ [[1, -1], [1, 1, 1], [1, 0, 0, 1, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1]]
def zzX_fateman_poly_F_3(n): """Fateman's GCD benchmark: sparse inputs (deg f ~ vars f) """ u = zzx_from_dict({n+1:1}) for i in xrange(1, n): u = zzX_add_term([u], zzX_const(i, 1), n+1) v = zzX_add_term(u, zzX_const(n-1, 2)) f = zzX_sqr(zzX_add_term([zzX_neg(v)], zzX_const(n, 1), n+1)) g = zzX_sqr(zzX_add_term([v], zzX_const(n, 1), n+1)) v = zzX_add_term(u, zzX_const(n-1, 1)) h = zzX_sqr(zzX_add_term([v], zzX_const(n, 1), n+1)) return zzX_mul(f,h), zzX_mul(g,h), h
def zzX_fateman_poly_F_3(n): """Fateman's GCD benchmark: sparse inputs (deg f ~ vars f) """ u = zzx_from_dict({n + 1: 1}) for i in xrange(1, n): u = zzX_add_term([u], zzX_const(i, 1), n + 1) v = zzX_add_term(u, zzX_const(n - 1, 2)) f = zzX_sqr(zzX_add_term([zzX_neg(v)], zzX_const(n, 1), n + 1)) g = zzX_sqr(zzX_add_term([v], zzX_const(n, 1), n + 1)) v = zzX_add_term(u, zzX_const(n - 1, 1)) h = zzX_sqr(zzX_add_term([v], zzX_const(n, 1), n + 1)) return zzX_mul(f, h), zzX_mul(g, h), h
def kronecker_mv(f, **flags): """Kronecker method for Z[X] polynomials. NOTE: This function is very slow even on small input. Use debug=True flag to see its progress, if any. """ symbols = f.symbols def mv_int_div(f, g): q = Poly((), *symbols) r = Poly((), *symbols) while not f.is_zero: lc_f, lc_g = f.LC, g.LC dv = lc_f % lc_g cf = lc_f / lc_g monom = monomial_div(f.LM, g.LM) if dv == 0 and monom is not None: q = q.add_term(cf, monom) f -= g.mul_term(cf, monom) else: r = r.add_term(*f.LT) f = f.kill_lead_term() return q, r def combinations(lisp, m): def recursion(fa, lisp, m): if m == 0: yield fa else: for i, fa2 in enumerate(lisp[0 : len(lisp) + 1 - m]): for el in recursion(zzx_mul(fa2, fa), list(lisp[i + 1:]), m - 1): yield el for i, fa in enumerate(lisp[0 : len(lisp) + 1 - m]): for el in recursion(fa, list(lisp[i + 1:]), m - 1): yield el debug = flags.get('debug', False) cont, f = f.as_primitive() N = len(symbols) max_exp = {} for v in symbols: max_exp[v] = 0 for coeff, monom in f.iter_terms(): for v, exp in zip(symbols, monom): if exp > max_exp[v]: max_exp[v] = exp symbols = sorted(symbols, reverse=True, key=lambda v: max_exp[v]) f = Poly(f, *symbols) d = max_exp[symbols[0]] + 1 terms, exps = {}, [] for i in xrange(0, len(symbols)): exps.append(d**i) for coeff, monom in f.iter_terms(): exp = 0 for i, expi in enumerate(monom): exp += expi * exps[i] terms[exp] = int(coeff) g, factors = zzx_from_dict(terms), [] try: for ff, k in zzx_factor(g)[1]: for i in xrange(0, k): factors.append(ff) except OverflowError: raise PolynomialError("input too large for multivariate Kronecker method") const, result, tested = 1, [], [] if debug: print "KRONECKER-MV: Z[x] #factors = %i ..." % (len(factors)) for k in range(1, len(factors)//2 + 1): for h in combinations(factors, k): if h in tested: continue n = zzx_degree(h) terms = {} for coeff in h: if not coeff: n = n-1 continue else: coeff = Integer(coeff) y_deg, n = n, n-1 monom = [0] * N for i in xrange(N): v_deg = y_deg % d y_deg = (y_deg - v_deg) // d monom[i] = v_deg monom = tuple(monom) if terms.has_key(monom): terms[monom] += coeff else: terms[monom] = coeff cand = Poly(terms, *symbols) if cand.is_one: continue if cand.LC.is_negative: cand = -cand; q, r = mv_int_div(f, cand) if r.is_zero: if debug: print "KRONECKER-MV: Z[X] factor found %s" % cand result.append(cand) f = q else: tested.append(h) if f.is_constant: const, f = f.LC, Poly(1, *symbols) break if f.is_one: break if not f.is_one: if debug: print "KRONECKER-MV: Z[X] factor found %s" % f result.append(f) factors = {} for ff in result: if factors.has_key(ff): factors[ff] += 1 else: factors[ff] = 1 return cont*const, sorted(factors.items())
def test_zzx_from_to_dict(): f = {8: 3, 5: 2, 0: 8} g = [3, 0, 0, 2, 0, 0, 0, 0, 8] assert zzx_from_dict(f) == g assert zzx_to_dict(g) == f
def test_zzx_factor(): assert zzx_factor([]) == (0, []) assert zzx_factor([7]) == (7, []) f = [1, 0, 0, 1, 1] for i in xrange(0, 20): assert zzx_factor(f) == (1, [(f, 1)]) assert zzx_factor([2,4]) == \ (2, [([1, 2], 1)]) assert zzx_factor([1,2,2]) == \ (1, [([1,2,2], 1)]) assert zzx_factor([18,12,2]) == \ (2, [([3, 1], 2)]) assert zzx_factor([-9,0,1]) == \ (-1, [([3,-1], 1), ([3, 1], 1)]) assert zzx_factor_sqf([-9,0,1]) == \ (-1, [[3,-1], [3, 1]]) assert zzx_factor([1,-6,11,-6]) == \ (1, [([1,-3], 1), ([1,-2], 1), ([1,-1], 1)]) assert zzx_factor_sqf([1,-6,11,-6]) == \ (1, [[1,-3], [1,-2], [1,-1]]) assert zzx_factor([-1,0,0,0,1,0,0]) == \ (-1, [([1,-1], 1), ([1, 1], 1), ([1, 0], 2), ([1, 0, 1], 1)]) f = [1080, 5184, 2099, 744, 2736, -648, 129, 0, -324] assert zzx_factor(f) == \ (1, [([5, 24, 9, 0, 12], 1), ([216, 0, 31, 0, -27], 1)]) f = [ -29802322387695312500000000000000000000, 0, 0, 0, 0, 2980232238769531250000000000000000, 0, 0, 0, 0, 1743435859680175781250000000000, 0, 0, 0, 0, 114142894744873046875000000, 0, 0, 0, 0, -210106372833251953125, 0, 0, 0, 0, 95367431640625 ] assert zzx_factor(f) == \ (-95367431640625, [([5, -1], 1), ([100, 10, -1], 2), ([625, 125, 25, 5, 1], 1), ([10000, -3000, 400, -20, 1], 2), ([10000, 2000, 400, 30, 1], 2)]) f = zzx_from_dict({10: 1, 0: -1}) F_0 = zzx_factor(f, cyclotomic=True) F_1 = zzx_factor(f, cyclotomic=False) assert F_0 == F_1 == \ (1, [([1,-1], 1), ([1, 1], 1), ([1,-1, 1,-1, 1], 1), ([1, 1, 1, 1, 1], 1)]) f = zzx_from_dict({10: 1, 0: 1}) F_0 = zzx_factor(f, cyclotomic=True) F_1 = zzx_factor(f, cyclotomic=False) assert F_0 == F_1 == \ (1, [([1, 0, 1], 1), ([1, 0, -1, 0, 1, 0, -1, 0, 1], 1)])
def kronecker_mv(f, **flags): """Kronecker method for Z[X] polynomials. NOTE: This function is very slow even on small input. Use debug=True flag to see its progress, if any. """ symbols = f.symbols def mv_int_div(f, g): q = Poly((), *symbols) r = Poly((), *symbols) while not f.is_zero: lc_f, lc_g = f.LC, g.LC dv = lc_f % lc_g cf = lc_f / lc_g monom = monomial_div(f.LM, g.LM) if dv == 0 and monom is not None: q = q.add_term(cf, monom) f -= g.mul_term(cf, monom) else: r = r.add_term(*f.LT) f = f.kill_lead_term() return q, r def combinations(lisp, m): def recursion(fa, lisp, m): if m == 0: yield fa else: for i, fa2 in enumerate(lisp[0:len(lisp) + 1 - m]): for el in recursion(zzx_mul(fa2, fa), list(lisp[i + 1:]), m - 1): yield el for i, fa in enumerate(lisp[0:len(lisp) + 1 - m]): for el in recursion(fa, list(lisp[i + 1:]), m - 1): yield el debug = flags.get('debug', False) cont, f = f.as_primitive() N = len(symbols) max_exp = {} for v in symbols: max_exp[v] = 0 for coeff, monom in f.iter_terms(): for v, exp in zip(symbols, monom): if exp > max_exp[v]: max_exp[v] = exp symbols = sorted(symbols, reverse=True, key=lambda v: max_exp[v]) f = Poly(f, *symbols) d = max_exp[symbols[0]] + 1 terms, exps = {}, [] for i in xrange(0, len(symbols)): exps.append(d**i) for coeff, monom in f.iter_terms(): exp = 0 for i, expi in enumerate(monom): exp += expi * exps[i] terms[exp] = int(coeff) g, factors = zzx_from_dict(terms), [] try: for ff, k in zzx_factor(g)[1]: for i in xrange(0, k): factors.append(ff) except OverflowError: raise PolynomialError( "input too large for multivariate Kronecker method") const, result, tested = 1, [], [] if debug: print "KRONECKER-MV: Z[x] #factors = %i ..." % (len(factors)) for k in range(1, len(factors) // 2 + 1): for h in combinations(factors, k): if h in tested: continue n = zzx_degree(h) terms = {} for coeff in h: if not coeff: n = n - 1 continue else: coeff = Integer(coeff) y_deg, n = n, n - 1 monom = [0] * N for i in xrange(N): v_deg = y_deg % d y_deg = (y_deg - v_deg) // d monom[i] = v_deg monom = tuple(monom) if terms.has_key(monom): terms[monom] += coeff else: terms[monom] = coeff cand = Poly(terms, *symbols) if cand.is_one: continue if cand.LC.is_negative: cand = -cand q, r = mv_int_div(f, cand) if r.is_zero: if debug: print "KRONECKER-MV: Z[X] factor found %s" % cand result.append(cand) f = q else: tested.append(h) if f.is_constant: const, f = f.LC, Poly(1, *symbols) break if f.is_one: break if not f.is_one: if debug: print "KRONECKER-MV: Z[X] factor found %s" % f result.append(f) factors = {} for ff in result: if factors.has_key(ff): factors[ff] += 1 else: factors[ff] = 1 return cont * const, sorted(factors.items())
def test_zzx_factor(): assert zzx_factor([ ]) == (0, []) assert zzx_factor([7]) == (7, []) f = [1,0,0,1,1] for i in xrange(0, 20): assert zzx_factor(f) == (1, [(f, 1)]) assert zzx_factor([2,4]) == \ (2, [([1, 2], 1)]) assert zzx_factor([1,2,2]) == \ (1, [([1,2,2], 1)]) assert zzx_factor([18,12,2]) == \ (2, [([3, 1], 2)]) assert zzx_factor([-9,0,1]) == \ (-1, [([3,-1], 1), ([3, 1], 1)]) assert zzx_factor_sqf([-9,0,1]) == \ (-1, [[3,-1], [3, 1]]) assert zzx_factor([1,-6,11,-6]) == \ (1, [([1,-3], 1), ([1,-2], 1), ([1,-1], 1)]) assert zzx_factor_sqf([1,-6,11,-6]) == \ (1, [[1,-3], [1,-2], [1,-1]]) assert zzx_factor([-1,0,0,0,1,0,0]) == \ (-1, [([1,-1], 1), ([1, 1], 1), ([1, 0], 2), ([1, 0, 1], 1)]) f = [1080, 5184, 2099, 744, 2736, -648, 129, 0, -324] assert zzx_factor(f) == \ (1, [([5, 24, 9, 0, 12], 1), ([216, 0, 31, 0, -27], 1)]) f = [-29802322387695312500000000000000000000, 0, 0, 0, 0, 2980232238769531250000000000000000, 0, 0, 0, 0, 1743435859680175781250000000000, 0, 0, 0, 0, 114142894744873046875000000, 0, 0, 0, 0, -210106372833251953125, 0, 0, 0, 0, 95367431640625] assert zzx_factor(f) == \ (-95367431640625, [([5, -1], 1), ([100, 10, -1], 2), ([625, 125, 25, 5, 1], 1), ([10000, -3000, 400, -20, 1], 2), ([10000, 2000, 400, 30, 1], 2)]) f = zzx_from_dict({10:1, 0:-1}) F_0 = zzx_factor(f, cyclotomic=True) F_1 = zzx_factor(f, cyclotomic=False) assert F_0 == F_1 == \ (1, [([1,-1], 1), ([1, 1], 1), ([1,-1, 1,-1, 1], 1), ([1, 1, 1, 1, 1], 1)]) f = zzx_from_dict({10:1, 0:1}) F_0 = zzx_factor(f, cyclotomic=True) F_1 = zzx_factor(f, cyclotomic=False) assert F_0 == F_1 == \ (1, [([1, 0, 1], 1), ([1, 0, -1, 0, 1, 0, -1, 0, 1], 1)])
def test_zzx_from_to_dict(): f = {8: 3, 5: 2, 0: 8} g = [3,0,0,2,0,0,0,0,8] assert zzx_from_dict(f) == g assert zzx_to_dict(g) == f