def poly_sqf(f, *symbols): """Compute square-free decomposition of an univariate polynomial. Given an univariate polynomial f over an unique factorization domain returns tuple (f_1, f_2, ..., f_n), where all A_i are co-prime and square-free polynomials and f = f_1 * f_2**2 * ... * f_n**n. >>> from sympy import * >>> x,y = symbols('xy') >>> p, q = poly_sqf(x*(x+1)**2, x) >>> p.as_basic() x >>> q.as_basic() 1 + x For more information on the implemented algorithm refer to: [1] M. Bronstein, Symbolic Integration I: Transcendental Functions, Second Edition, Springer-Verlang, 2005 [2] J. von zur Gathen, J. Gerhard, Modern Computer Algebra, Second Edition, Cambridge University Press, 2003 """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") if f.is_multivariate: raise MultivariatePolyError(f) coeff, f = f.as_primitive() sqf = [] h = f.diff() g = poly_gcd(f, h) p = poly_div(f, g)[0] q = poly_div(h, g)[0] p, q = poly_reduce(p, q) while True: h = q - p.diff() if h.is_zero: break g = poly_gcd(p, h) sqf.append(g) p = poly_div(p, g)[0] q = poly_div(h, g)[0] p, q = poly_reduce(p, q) sqf.append(p) head, tail = sqf[0], sqf[1:] head = head.mul_term(coeff) return [head] + tail
def poly_gcd(f, g, *symbols): """Compute greatest common divisor of two polynomials. Given two univariate polynomials, subresultants are used to compute the GCD. In multivariate case Groebner basis approach is used together with f*g = gcd(f, g)*lcm(f, g) well known formula. For more information on the implemented algorithm refer to: [1] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and Algorithms, Springer, Second Edition, 1997, pp. 187 """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") f, g = f.unify_with(g) symbols, flags = f.symbols, f.flags if f.is_zero and g.is_zero: return f if f.is_constant: if f.is_zero: cont, g = g.as_primitive() return g.mul_term(cont / g.LC) if f.is_one: return f if g.is_constant: if g.is_zero: cont, f = f.as_primitive() return f.mul_term(cont / f.LC) if g.is_one: return g if f.is_monomial and g.is_monomial: monom = monomial_gcd(f.LM, g.LM) fc, gc = f.LC, g.LC if fc.is_Rational and gc.is_Rational: coeff = Integer(igcd(fc.p, gc.p)) else: coeff = S.One return Poly((coeff, monom), *symbols, **flags) cf, f = f.as_primitive() cg, g = g.as_primitive() gcd = igcd(int(cf), int(cg)) if f.is_multivariate: h = poly_div(f * g, poly_lcm(f, g))[0] else: h = poly_subresultants(f, g, res=False)[-1] if gcd != 1: return h.mul_term(gcd / h.LC) else: return h.as_monic()
def poly_lcm(f, g, *symbols): """Computes least common multiple of two polynomials. Given two univariate polynomials, the LCM is computed via f*g = gcd(f, g)*lcm(f, g) formula. In multivariate case, we compute the unique generator of the intersection of the two ideals, generated by f and g. This is done by computing a Groebner basis, with respect to any lexicographic ordering, of t*f and (1 - t)*g, where t is an unrelated symbol and filtering out solution that does not contain t. For more information on the implemented algorithm refer to: [1] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and Algorithms, Springer, Second Edition, 1997, pp. 187 """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") f, g = f.unify_with(g) symbols, flags = f.symbols, f.flags if f.is_monomial and g.is_monomial: monom = monomial_lcm(f.LM, g.LM) fc, gc = f.LC, g.LC if fc.is_Rational and gc.is_Rational: coeff = Integer(ilcm(fc.p, gc.p)) else: coeff = S.One return Poly((coeff, monom), *symbols, **flags) fc, f = f.as_primitive() gc, g = g.as_primitive() lcm = ilcm(int(fc), int(gc)) if f.is_multivariate: t = Symbol('t', dummy=True) lex = {'order': 'lex'} f_monoms = [(1, ) + monom for monom in f.monoms] F = Poly((f.coeffs, f_monoms), t, *symbols, **lex) g_monoms = [ (0,) + monom for monom in g.monoms ] + \ [ (1,) + monom for monom in g.monoms ] g_coeffs = list(g.coeffs) + [-coeff for coeff in g.coeffs] G = Poly(dict(zip(g_monoms, g_coeffs)), t, *symbols, **lex) def independent(h): return all(not monom[0] for monom in h.monoms) H = [h for h in poly_groebner((F, G)) if independent(h)] if lcm != 1: h_coeffs = [coeff * lcm for coeff in H[0].coeffs] else: h_coeffs = H[0].coeffs h_monoms = [monom[1:] for monom in H[0].monoms] return Poly(dict(zip(h_monoms, h_coeffs)), *symbols, **flags) else: h = poly_div(f * g, poly_gcd(f, g))[0] if lcm != 1: return h.mul_term(lcm / h.LC) else: return h.as_monic()
def poly_gcd(f, g, *symbols): """Compute greatest common divisor of two polynomials. Given two univariate polynomials, subresultants are used to compute the GCD. In multivariate case Groebner basis approach is used together with f*g = gcd(f, g)*lcm(f, g) well known formula. For more information on the implemented algorithm refer to: [1] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and Algorithms, Springer, Second Edition, 1997, pp. 187 """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") f, g = f.unify_with(g) symbols, flags = f.symbols, f.flags if f.is_zero and g.is_zero: return f if f.is_constant: if f.is_zero: cont, g = g.as_primitive() return g.mul_term(cont / g.LC) if f.is_one: return f if g.is_constant: if g.is_zero: cont, f = f.as_primitive() return f.mul_term(cont / f.LC) if g.is_one: return g if f.is_monomial and g.is_monomial: monom = monomial_gcd(f.LM, g.LM) fc, gc = f.LC, g.LC if fc.is_Rational and gc.is_Rational: coeff = Integer(igcd(fc.p, gc.p)) else: coeff = S.One return Poly((coeff, monom), *symbols, **flags) cf, f = f.as_primitive() cg, g = g.as_primitive() gcd = igcd(int(cf), int(cg)) if f.is_multivariate: h = poly_div(f*g, poly_lcm(f, g))[0] else: h = poly_subresultants(f, g)[-1] if gcd != 1: return h.mul_term(gcd / h.LC) else: return h.as_monic()
def poly_lcm(f, g, *symbols): """Computes least common multiple of two polynomials. Given two univariate polynomials, the LCM is computed via f*g = gcd(f, g)*lcm(f, g) formula. In multivariate case, we compute the unique generator of the intersection of the two ideals, generated by f and g. This is done by computing a Groebner basis, with respect to any lexicographic ordering, of t*f and (1 - t)*g, where t is an unrelated symbol and filtering out solution that does not contain t. For more information on the implemented algorithm refer to: [1] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and Algorithms, Springer, Second Edition, 1997, pp. 187 """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") f, g = f.unify_with(g) symbols, flags = f.symbols, f.flags if f.is_monomial and g.is_monomial: monom = monomial_lcm(f.LM, g.LM) fc, gc = f.LC, g.LC if fc.is_Rational and gc.is_Rational: coeff = Integer(ilcm(fc.p, gc.p)) else: coeff = S.One return Poly((coeff, monom), *symbols, **flags) fc, f = f.as_primitive() gc, g = g.as_primitive() lcm = ilcm(int(fc), int(gc)) if f.is_multivariate: t = Symbol('t', dummy=True) lex = { 'order' : 'lex' } f_monoms = [ (1,) + monom for monom in f.monoms ] F = Poly((f.coeffs, f_monoms), t, *symbols, **lex) g_monoms = [ (0,) + monom for monom in g.monoms ] + \ [ (1,) + monom for monom in g.monoms ] g_coeffs = list(g.coeffs) + [ -coeff for coeff in g.coeffs ] G = Poly(dict(zip(g_monoms, g_coeffs)), t, *symbols, **lex) def independent(h): return all(not monom[0] for monom in h.monoms) H = [ h for h in poly_groebner((F, G)) if independent(h) ] if lcm != 1: h_coeffs = [ coeff*lcm for coeff in H[0].coeffs ] else: h_coeffs = H[0].coeffs h_monoms = [ monom[1:] for monom in H[0].monoms ] return Poly(dict(zip(h_monoms, h_coeffs)), *symbols, **flags) else: h = poly_div(f * g, poly_gcd(f, g))[0] if lcm != 1: return h.mul_term(lcm / h.LC) else: return h.as_monic()