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 poly_factors(f, *symbols, **flags): """Factor polynomials over rationals. >>> from sympy import * >>> x, y = symbols("x y") >>> poly_factors(x**2 - y**2, x, y) (1, [(Poly(x - y, x, y), 1), (Poly(x + y, x, y), 1)]) """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") denom, f = f.as_integer() if f.is_univariate: coeffs = map(int, f.iter_all_coeffs()) content, factors = zzx_factor(coeffs) for i in xrange(len(factors)): factor, k = factors[i] n = zzx_degree(factor) terms = {} for j, coeff in enumerate(factor): if coeff != 0: terms[(n - j, )] = Integer(coeff) factors[i] = Poly(terms, *f.symbols), k else: content, factors = kronecker_mv(f, **flags) return Rational(content, denom), factors
def poly_factors(f, *symbols, **flags): """Factor polynomials over rationals. >>> from sympy import * >>> x, y = symbols("x y") >>> poly_factors(x**2 - y**2, x, y) (1, [(Poly(x - y, x, y), 1), (Poly(x + y, x, y), 1)]) """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") denom, f = f.as_integer() if f.is_univariate: coeffs = map(int, f.iter_all_coeffs()) content, factors = zzx_factor(coeffs) for i in xrange(len(factors)): factor, k = factors[i] n = zzx_degree(factor) terms = {} for j, coeff in enumerate(factor): if coeff != 0: terms[(n-j,)] = Integer(coeff) factors[i] = Poly(terms, *f.symbols), k else: content, factors = kronecker_mv(f, **flags) return Rational(content, denom), factors
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 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())