Пример #1
0
def groebner(f, var=None, order=None, reduced=True):
    """Computes the (reduced) Groebner base of given polynomials.

    Thin wrapper returning SymPy expressions from L{groebner_.groebner}.

    """

    g = groebner_.groebner(f, var, order, reduced)
    return map(lambda p: p.sympy_expr, g)
Пример #2
0
def lcm(f, g, var=None, order=None, coeff=None):
    """Least common multiple.

    Usage:
    ======
        Input are two polynomials, either as SymPy expressions or as
        instances of Polynomial. In the first case, the variables and
        monomial order can be specified with 'var' and 'order',
        respectively.

        If 'coeff' is set to 'int', the content of each polynomial is
        checked and their lcm multiplied to the result. Otherwise it
        is monic, that is, of leading coefficient 1.

        The output's type is Polynomial, but there is a wrapper, see
        L{wrapper.lcm}.

    Notes:
    ======
        With only one variable, the gcd is used to get the lcm from
        the product, via f*g = gcd(f, g)*lcm(f, g).

        In the univariate case, we compute the unique generator of the
        intersection of the two ideals, generated by f and g. This is
        done by computing a lexicographic Groebner base of
        [t*f. (t-1)*g], with t a dummy variable at the first place,
        then filtering trough the base elements not containing t.

    Examples:
    =========
        >>> x, y = symbols('xy')
        >>> print lcm(4*x**2*y, 6*x*y**2)
        x**2*y**2
        >>> print lcm(4*x**2*y, 6*x*y**2, coeff='int')
        12*x**2*y**2

    References:
    ===========
        Cox, Little, O'Shea: Ideals, Varieties and Algorithms,
        Springer, 2. edition, p. 187

    See also L{div}, L{gcd}.
        
    """

    # Check if f is a Polynomial already, g is assumed to match.
    if not isinstance(f, Polynomial):
        f = sympify(f)
        g = sympify(g)
        if var is None:
            var = merge_var(f.atoms(type=Symbol), g.atoms(type=Symbol))
        f = Polynomial(f, var=var, order=order)
        g = Polynomial(g, var=var, order=order)

    # Check if we need to keep an integer factor.
    if coeff == 'int':
        cf, f = f.as_primitive()
        cg, g = g.as_primitive()
        cf, cg = int(cf), int(cg)
        c = Integer(cf*cg/numbers.gcd(cf, cg))
    else:
        c = S.One

    if len(f.var) == 0: # Constant result.
        return Polynomial(c, var=f.var, order=f.order)
    elif len(f.var) == 1: # Use gcd to get univariate lcm.
        gcd_temp = gcd(f, g)
        q, r = div(f*g, gcd_temp)
        assert r.sympy_expr is S.Zero
        lc, f = q.as_monic()
    else:
        # Compute a lexicographic Groebner base of the ideal generated
        # by t*f and (t-1)*g, with unrelated t.
        from sympy.polynomials import groebner_

        t = Symbol('t', dummy=True)
        var = [t] + f.var
        G = groebner_.groebner([Polynomial(t*f.sympy_expr,
                                           var=var, order='1-el'),
                                Polynomial((t-1)*g.sympy_expr,
                                           var=var, order='1-el')],
                               reduced=True)
        # Now intersect this result with the polynomial ring in the
        # var in `var', that is, eliminate t.
        I = filter(lambda p: t not in p.sympy_expr.atoms(type=Symbol), G)
        # The intersection should be a principal ideal, that is generated
        # by a single polynomial.
        if not len(I) == 1:
            raise PolynomialException("No single generator for intersection.")
        f = Polynomial(I[0].sympy_expr, var=f.var, order=f.order)

    return Polynomial(coeffs=tuple([(c*t[0],) + t[1:] for t in f.coeffs]),
                      var=f.var, order=f.order)
Пример #3
0
def solve_system(eqs, var=None, order=None):
    """Solves a system of polynomial equations.

    Usage:
    ======
        Assumes to get a list of polynomials, either as SymPy
        expressions or instances of Polynomial. In the first case, you
        should specify the variables and monomial order through 'var'
        and 'order'. Otherwise, the polynomials should have matching
        variables and orders already. Only the first polynomial is
        checked for its type.

        This algorithm uses variable elimination and only works for
        zero-dimensional varieties, that is, a finite number of
        solutions, which is currently not tested.

    Examples:
    =========
        >>> x, y = symbols('xy')
        >>> f = y - x
        >>> g = x**2 + y**2 - 1
        >>> solve_system([f, g])
        [(-(1/2)**(1/2), -(1/2)**(1/2)), ((1/2)**(1/2), (1/2)**(1/2))]

    References:
    ===========
        Cox, Little, O'Shea: Ideals, Varieties and Algorithms,
        Springer, 2. edition, p. 113

    """

    def is_uv(f):
        """Is an instance of Polynomial univariate in its last variable?"""
        for term in f.coeffs:
            for exponent in term[1:-1]:
                if exponent > 0:
                    return False
        return True

    if not isinstance(eqs, list):
        eqs = [eqs]
    if not isinstance(eqs[0], Polynomial):
        if var is None:
            var = merge_var(*[f.atoms(type=Symbol) for f in eqs])
        eqs = [Polynomial(f, var=var, order='lex') for f in eqs]
    else:
        eqs = [Polynomial(f.sympy_expr, var=f.var, order='lex') for f in eqs]

    # First compute a Groebner base with the polynomials,
    # with lexicographic ordering, so that the last polynomial is
    # univariate and can be solved.
    gb = groebner_.groebner(eqs)

    # Now filter the the base elements, to get only the univariate ones.
    eliminated = filter(is_uv, gb)
    if len(eliminated) != 1:
        raise PolynomialException("System currently not solvable.")

    # Try to solve the polynomials with var eliminated.
    f = eliminated[0]
    partial_solutions = set(roots(f.sympy_expr, var=f.var[-1]))

    # No solutions were found.
    # TODO: Check if there exist some anyways?
    if len(partial_solutions) == 0:
        return []

    # Is this the last equation, that is, deepest hierarchy?
    if len(gb) == 1:
        return map(lambda s:(s,), partial_solutions)

    # Finally, call this function recursively for each root replacing
    # the corresponding variable in the system.
    result = []
    for r in partial_solutions:
        new_system = []
        for eq in gb[:-1]:
            new_eq = eq.sympy_expr.subs(eq.var[-1], r).expand()
            if new_eq is not S.Zero:
                new_system.append(
                    Polynomial(new_eq, var=eq.var[:-1], order='lex'))
        if not new_system:
            return []
        for nps in solve_system(new_system):
            result.append(nps + (r,))

    # With symbols, __nonzero__ returns a StrictInequality, Exception.
    try: result.sort()
    except: pass

    return result