예제 #1
0
def test_polys():
    x = Symbol("x")
    f = Poly(x, x)
    g = lambda x: x

    for c in (IntegerPoly, IntegerPoly(x, x), Poly, Poly(x, x)):
        check(c)

    for c in (RootOf, RootOf(f,
                             0), RootsOf, RootsOf(x,
                                                  x), RootSum, RootSum(g, f)):
        check(c)
예제 #2
0
def poly_sturm(f, *symbols):
    """Computes the Sturm sequence of a given polynomial.

       Given an univariate, square-free polynomial f(x) returns an
       associated Sturm sequence f_0(x), ..., f_n(x) defined by:

           f_0(x), f_1(x) = f(x), f'(x)
           f_n = -rem(f_{n-2}(x), f_{n-1}(x))

       For more information on the implemented algorithm refer to:

       [1] J.H. Davenport, Y. Siret, E. Tournier, Computer Algebra
           Systems and Algorithms for Algebraic Computation,
           Academic Press, London, 1988, pp. 124-128

    """
    if not isinstance(f, Poly):
        f = Poly(f, *symbols)
    elif symbols:
        raise SymbolsError("Redundant symbols were given")

    if f.is_multivariate:
        raise MultivariatePolyError(f)
    else:
        f = f.as_squarefree()

    sturm = [f, f.diff()]

    while not sturm[-1].is_zero:
        sturm.append(-poly_div(sturm[-2], sturm[-1])[1])

    return sturm[:-1]
예제 #3
0
    def __new__(cls, f, x=None):
        if not isinstance(f, Poly):
            f = Poly(f, x)
        elif x is not None:
            raise SymbolsError("Redundant symbols were given")

        if f.is_multivariate:
            raise MultivariatePolyError(f)

        return Basic.__new__(cls, f)
예제 #4
0
    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
예제 #5
0
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")

    symbols = list(f.symbols)

    try:
        denom, F = f.as_integer()
    except CoefficientError:
        other = set([])

        for coeff in f.iter_coeffs():
            other |= coeff.atoms(Symbol)

        symbols += sorted(other)

        F = Poly(f, *symbols)
        denom, F = F.as_integer()

    cont, factors = zzX_factor(zzX_from_poly(F))

    for i, (h, k) in enumerate(factors):
        h = zzX_to_poly(h, *symbols)

        if f.symbols != symbols:
            h = h.as_poly(*f.symbols)

        factors[i] = (h, k)

    return Rational(cont, denom), factors
예제 #6
0
def poly_root_factors(f, *symbols, **flags):
    """Returns all factors of an univariate polynomial.

       >>> from sympy import *
       >>> x,y = symbols('xy')

       >>> factors = poly_root_factors(x**2-y, x)

       >>> set(f.as_basic() for f in factors)
       set([x + y**(1/2), x - y**(1/2)])
    """
    if not isinstance(f, Poly):
        f = Poly(f, *symbols)
    elif symbols:
        raise SymbolsError("Redundant symbols were given")

    if f.is_multivariate:
        raise MultivariatePolyError(f)
    else:
        x = f.symbols[0]

    if flags.has_key('multiple'):
        del flags['multiple']

    zeros = roots(f, **flags)

    if not zeros:
        return [f]
    else:
        factors, N = [], 0

        for r, n in zeros.iteritems():
            h = Poly([(S.One, 1), (-r, 0)], x)
            factors, N = factors + [h] * n, N + n

        if N < f.degree:
            g = reduce(lambda p, q: p * q, factors)
            factors.append(poly_div(f, g)[0])

        return factors
예제 #7
0
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
예제 #8
0
def roots(f, *symbols, **flags):
    """Computes symbolic roots of an univariate polynomial.

       Given an univariate  polynomial f with symbolic coefficients,
       returns a dictionary with its roots and their multiplicities.

       Only roots expressible via radicals will be returned.  To get
       a complete set of roots use RootOf class or numerical methods
       instead. By default cubic and quartic formulas aren't used in
       the algorithm because of unreadable output. To enable them
       set cubics=True or quartics=True respectively.

       To get roots from a specific domain set the 'domain' flag with
       one of the following specifiers: Z, Q, R, I, C. By default all
       roots are returned (this is equivalent to setting domain='C').

       By default a dictionary is returned giving a compact result in
       case of multiple roots.  However to get a tuple containing all
       those roots set the 'multiple' flag to True.

       >>> from sympy import *
       >>> x,y = symbols('xy')

       >>> roots(x**2 - 1, x)
       {1: 1, -1: 1}

       >>> roots(x**2 - y, x)
       {y**(1/2): 1, -y**(1/2): 1}

    """
    if not isinstance(f, Poly):
        f = Poly(f, *symbols)
    elif symbols:
        raise SymbolsError("Redundant symbols were given")

    if f.is_multivariate:
        raise MultivariatePolyError(f)

    def roots_trivial(g):
        if g.length == 1:
            if g.is_constant:
                return []
            else:
                return [S.Zero] * g.degree

        (k, ), g = g.as_reduced()

        if k == 0:
            zeros = []
        else:
            zeros = [S.Zero] * k

        if g.length == 2:
            zeros += roots_binomial(g)
        else:
            x = g.symbols[0]

            for i in [S.NegativeOne, S.One]:
                if g(i).expand() is S.Zero:
                    g = poly_div(g, x - i)[0]
                    zeros.append(i)
                    break

            n = g.degree

            if n == 1:
                zeros += roots_linear(g)
            elif n == 2:
                zeros += roots_quadratic(g)
            elif n == 3:
                if flags.get('cubics', False):
                    # TODO: now we can used factor() not only
                    #       for cubic polynomials. See #1158
                    try:
                        _, factors = poly_factors(g)

                        if len(factors) == 1:
                            raise PolynomialError

                        for factor, k in factors:
                            zeros += roots(factor, multiple=True) * k
                    except PolynomialError:
                        zeros += roots_cubic(g)
            elif n == 4:
                if flags.get('quartics', False):
                    zeros += roots_quartic(g)

        return zeros

    multiple = flags.get('multiple', False)

    if f.length == 1:
        if f.is_constant:
            if multiple:
                return []
            else:
                return {}
        else:
            result = {S.Zero: f.degree}
    else:
        (k, ), f = f.as_reduced()

        if k == 0:
            result = {}
        else:
            result = {S.Zero: k}

        if f.degree == 1:
            result[roots_linear(f)[0]] = 1
        else:
            factors = poly_decompose(f)

            zeros, g = {}, factors[0]

            for i, h in enumerate(poly_sqf(g)):
                for zero in roots_trivial(h):
                    if zeros.has_key(zero):
                        zeros[zero] += i + 1
                    else:
                        zeros[zero] = i + 1

            for factor in factors[1:]:
                previous, zeros = zeros.copy(), {}

                for zero, i in previous.iteritems():
                    g = factor.sub_term(zero, (0, ))

                    for j, h in enumerate(poly_sqf(g)):
                        for zero in roots_trivial(h):
                            if zeros.has_key(zero):
                                zeros[zero] += i * (j + 1)
                            else:
                                zeros[zero] = i * (j + 1)

            result.update(zeros)

    domain = flags.get('domain', None)

    if domain not in [None, 'C']:
        handlers = {
            'Z': lambda r: r.is_Integer,
            'Q': lambda r: r.is_Rational,
            'R': lambda r: r.is_real,
            'I': lambda r: r.is_imaginary,
        }

        try:
            query = handlers[domain]
        except KeyError:
            raise ValueError("Invalid domain: %s" % domain)

        for zero in dict(result).iterkeys():
            if not query(zero):
                del result[zero]

    predicate = flags.get('predicate', None)

    if predicate is not None:
        for zero in dict(result).iterkeys():
            if not predicate(zero):
                del result[zero]

    if not multiple:
        return result
    else:
        zeros = []

        for zero, k in result.iteritems():
            zeros.extend([zero] * k)

        return zeros
예제 #9
0
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())
예제 #10
0
def number_of_real_roots(f, *symbols, **flags):
    """Returns the number of distinct real roots of f in (inf, sup].

       >>> from sympy import *
       >>> x,y = symbols('xy')

       >>> f = Poly(x**2 - 1, x)

       Count real roots in the (-oo, oo) interval:

       >>> number_of_real_roots(f)
       2

       Count real roots in the (0, 2) interval:

       >>> number_of_real_roots(f, inf=0, sup=2)
       1

       Count real roots in the (sqrt(2), oo) interval:

       >>> number_of_real_roots(f, inf=sqrt(2))
       0

       For more information on the implemented algorithm refer to:

       [1] J.H. Davenport, Y. Siret, E. Tournier, Computer Algebra
           Systems and Algorithms for Algebraic Computation,
           Academic Press, London, 1988, pp. 124-128
    """
    def sign_changes(seq):
        count = 0

        for i in xrange(1, len(seq)):
            if (seq[i-1] < 0 and seq[i] >= 0) or \
               (seq[i-1] > 0 and seq[i] <= 0):
                count += 1

        return count

    if not isinstance(f, Poly):
        f = Poly(f, *symbols)
    elif symbols:
        raise SymbolsError("Redundant symbols were given")

    if f.is_multivariate:
        raise MultivariatePolyError(f)

    if f.degree < 1:
        return 0

    inf = flags.get('inf', None)

    if inf is not None:
        inf = sympify(inf)

        if not inf.is_number:
            raise ValueError("Not a number: %s" % inf)
        elif abs(inf) is S.Infinity:
            inf = None

    sup = flags.get('sup', None)

    if sup is not None:
        sup = sympify(sup)

        if not sup.is_number:
            raise ValueError("Not a number: %s" % sup)
        elif abs(sup) is S.Infinity:
            sup = None

    sturm = poly_sturm(f)

    if inf is None:
        signs_inf = sign_changes([s.LC * (-1)**s.LM[0] for s in sturm])
    else:
        signs_inf = sign_changes([s(inf) for s in sturm])

    if sup is None:
        signs_sup = sign_changes([s.LC for s in sturm])
    else:
        signs_sup = sign_changes([s(sup) for s in sturm])

    return abs(signs_inf - signs_sup)
예제 #11
0
def roots(f, *symbols, **flags):
    """Computes symbolic roots of an univariate polynomial.

       Given an univariate  polynomial f with symbolic coefficients,
       returns a dictionary with its roots and their multiplicities.

       Only roots expressible via radicals will be returned.  To get
       a complete set of roots use RootOf class or numerical methods
       instead. By default cubic and quartic formulas are used in
       the algorithm. To disable them because of unreadable output
       set cubics=False or quartics=False respectively.

       To get roots from a specific domain set the 'domain' flag with
       one of the following specifiers: Z, Q, R, I, C. By default all
       roots are returned (this is equivalent to setting domain='C').

       By default a dictionary is returned giving a compact result in
       case of multiple roots.  However to get a tuple containing all
       those roots set the 'multiple' flag to True.

       >>> from sympy import *
       >>> x,y = symbols('xy')

       >>> roots(x**2 - 1, x)
       {1: 1, -1: 1}

       >>> roots(x**2 - y, x)
       {y**(1/2): 1, -y**(1/2): 1}

    """
    if not isinstance(f, Poly):
        f = Poly(f, *symbols)
    elif symbols:
        raise SymbolsError("Redundant symbols were given")

    if f.is_multivariate:
        raise MultivariatePolyError(f)

    def _update_dict(result, root, k):
        if root in result:
            result[root] += k
        else:
            result[root] = k

    def _try_decompose(f):
        """Find roots using functional decomposition. """
        factors = poly_decompose(f)
        result, g = {}, factors[0]

        for i, h in enumerate(poly_sqf(g)):
            for r in _try_heuristics(h):
                _update_dict(result, r, i + 1)

        for factor in factors[1:]:
            last, result = result.copy(), {}

            for last_r, i in last.iteritems():
                g = factor.sub_term(last_r, (0, ))

                for j, h in enumerate(poly_sqf(g)):
                    for r in _try_heuristics(h):
                        _update_dict(result, r, i * (j + 1))

        return result

    def _try_heuristics(f):
        """Find roots using formulas and some tricks. """
        if f.length == 1:
            if f.is_constant:
                return []
            else:
                return [S(0)] * f.degree

        if f.length == 2:
            if f.degree == 1:
                return roots_linear(f)
            else:
                return roots_binomial(f)

        x, result = f.symbols[0], []

        for i in [S(-1), S(1)]:
            if f(i).expand().is_zero:
                f = poly_div(f, x - i)[0]
                result.append(i)
                break

        n = f.degree

        if n == 1:
            result += roots_linear(f)
        elif n == 2:
            result += roots_quadratic(f)
        elif n == 3 and flags.get('cubics', True):
            result += roots_cubic(f)
        elif n == 4 and flags.get('quartics', False):
            result += roots_quartic(f)

        return result

    multiple = flags.get('multiple', False)

    if f.length == 1:
        if f.is_constant:
            if multiple:
                return []
            else:
                return {}
        else:
            result = {S(0): f.degree}
    else:
        (k, ), f = f.as_reduced()

        if k == 0:
            zeros = {}
        else:
            zeros = {S(0): k}

        result = {}

        if f.length == 2:
            if f.degree == 1:
                result[roots_linear(f)[0]] = 1
            else:
                for r in roots_binomial(f):
                    _update_dict(result, r, 1)
        elif f.degree == 2:
            for r in roots_quadratic(f):
                _update_dict(result, r, 1)
        else:
            try:
                _, factors = poly_factors(f)

                if len(factors) == 1 and factors[0][1] == 1:
                    raise CoefficientError

                for factor, k in factors:
                    for r in _try_heuristics(factor):
                        _update_dict(result, r, k)
            except CoefficientError:
                result = _try_decompose(f)

        result.update(zeros)

    domain = flags.get('domain', None)

    if domain not in [None, 'C']:
        handlers = {
            'Z': lambda r: r.is_Integer,
            'Q': lambda r: r.is_Rational,
            'R': lambda r: r.is_real,
            'I': lambda r: r.is_imaginary,
        }

        try:
            query = handlers[domain]
        except KeyError:
            raise ValueError("Invalid domain: %s" % domain)

        for zero in dict(result).iterkeys():
            if not query(zero):
                del result[zero]

    predicate = flags.get('predicate', None)

    if predicate is not None:
        for zero in dict(result).iterkeys():
            if not predicate(zero):
                del result[zero]

    if not multiple:
        return result
    else:
        zeros = []

        for zero, k in result.iteritems():
            zeros.extend([zero] * k)

        return zeros
예제 #12
0
def test_Roots():
    f = Poly(x**17 + 2 * x - 1, x)
    assert str(RootsOf(f)) == "RootsOf(x**17 + 2*x - 1, x)"
    assert str(RootOf(f, 0)) == "RootOf(x**17 + 2*x - 1, x, index=0)"
    assert str(RootSum(Lambda(z, z**2),
                       f)) == "RootSum(Lambda(_z, _z**2), x**17 + 2*x - 1, x)"
예제 #13
0
def test_Poly():
    assert str(Poly(0, x)) == "Poly(0, x)"
    assert str(Poly(1, x)) == "Poly(1, x)"
    assert str(Poly(x, x)) == "Poly(x, x)"
    assert str(Poly(2 * x + 1, x)) == "Poly(2*x + 1, x)"
    assert str(Poly(2 * x - 1, x)) == "Poly(2*x - 1, x)"
    assert str(Poly(-1, x)) == "Poly(-1, x)"
    assert str(Poly(-x, x)) == "Poly(-x, x)"
    assert str(Poly(-2 * x + 1, x)) == "Poly(-2*x + 1, x)"
    assert str(Poly(-2 * x - 1, x)) == "Poly(-2*x - 1, x)"
    assert str(Poly(x - 1, x, order='lex')) == "Poly(x - 1, x)"
    assert str(Poly(x**2 + 1 + y, x)) == "Poly(x**2 + 1 + y, x)"
    assert str(Poly(x**2 - 1 + y, x)) == "Poly(x**2 - 1 + y, x)"
    assert str(Poly(-x * y * z + x * y - 1, x, y,
                    z)) == "Poly(-x*y*z + x*y - 1, x, y, z)"
    assert str(Poly(-w*x**21*y**7*z + (1 + w)*z**3 - 2*x*z + 1, x, y, z)) == \
        "Poly(-w*x**21*y**7*z + (1 + w)*z**3 - 2*x*z + 1, x, y, z)"
    assert str(Poly(x*y*z**2 - 27*x, x, y, z, order='lex')) == \
        "Poly(x*y*z**2 - 27*x, x, y, z, order='lex')"
    assert str(Poly(x*y*z**2 - 27*x, x, y, z, order='grlex')) == \
        "Poly(x*y*z**2 - 27*x, x, y, z)"
    assert str(Poly(x*y*z**2 - 27*x, x, y, z, order='grevlex')) == \
        "Poly(x*y*z**2 - 27*x, x, y, z, order='grevlex')"
예제 #14
0
def test_Poly():
    sT(Poly(7, x), "Poly([(Integer(7), (0,))], Symbol('x'), order='grlex')")
    sT(Poly(2*x*y + 7, x, y), "Poly([(Integer(2), (1, 1)), (Integer(7), (0, 0))], Symbol('x'), Symbol('y'), order='grlex')")
    sT(Poly(2*x*y - 7, x, y, order='grevlex'), "Poly([(Integer(2), (1, 1)), (Integer(-7), (0, 0))], Symbol('x'), Symbol('y'), order='grevlex')")