(f, *gens, **flags)
Computes symbolic roots of a univariate polynomial.

    Given a univariate polynomial f with symbolic coefficients (or
    a list of the polynomial's 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 ``filter`` flag with
    one of the following specifiers: Z, Q, R, I, C. By default all
    roots are returned (this is equivalent to setting ``filter='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.

    Examples
    ========

    >>> from sympy import Poly, roots
    >>> from sympy.abc import x, y

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

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

    >>> p = Poly(x**2-y, x, y)

    >>> roots(Poly(p, x))
    {-sqrt(y): 1, sqrt(y): 1}

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

    >>> roots([1, 0, -1])
    {-1: 1, 1: 1}
Computes symbolic roots of a univariate polynomial.
Computes symbolic roots of a univariate polynomial .
def roots(f, *gens, **flags):
    """
    Computes symbolic roots of a univariate polynomial.

    Given a univariate polynomial f with symbolic coefficients (or
    a list of the polynomial's 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 ``filter`` flag with
    one of the following specifiers: Z, Q, R, I, C. By default all
    roots are returned (this is equivalent to setting ``filter='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.

    Examples
    ========

    >>> from sympy import Poly, roots
    >>> from sympy.abc import x, y

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

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

    >>> p = Poly(x**2-y, x, y)

    >>> roots(Poly(p, x))
    {-sqrt(y): 1, sqrt(y): 1}

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

    >>> roots([1, 0, -1])
    {-1: 1, 1: 1}

    """
    from sympy.polys.polytools import to_rational_coeffs
    flags = dict(flags)

    auto = flags.pop('auto', True)
    cubics = flags.pop('cubics', True)
    quartics = flags.pop('quartics', True)
    quintics = flags.pop('quintics', False)
    multiple = flags.pop('multiple', False)
    filter = flags.pop('filter', None)
    predicate = flags.pop('predicate', None)

    if isinstance(f, list):
        if gens:
            raise ValueError('redundant generators given')

        x = Dummy('x')

        poly, i = {}, len(f) - 1

        for coeff in f:
            poly[i], i = sympify(coeff), i - 1

        f = Poly(poly, x, field=True)
    else:
        try:
            f = Poly(f, *gens, **flags)
        except GeneratorsNeeded:
            if multiple:
                return []
            else:
                return {}

        if f.is_multivariate:
            raise PolynomialError('multivariate polynomials are not supported')

    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, roots = f.decompose(), []

        for root in _try_heuristics(factors[0]):
            roots.append(root)

        for factor in factors[1:]:
            previous, roots = list(roots), []

            for root in previous:
                g = factor - Poly(root, f.gen)

                for root in _try_heuristics(g):
                    roots.append(root)

        return roots

    def _try_heuristics(f):
        """Find roots using formulas and some tricks. """
        if f.is_ground:
            return []
        if f.is_monomial:
            return [S(0)]*f.degree()

        if f.length() == 2:
            if f.degree() == 1:
                return list(map(cancel, roots_linear(f)))
            else:
                return roots_binomial(f)

        result = []

        for i in [-1, 1]:
            if not f.eval(i):
                f = f.quo(Poly(f.gen - i, f.gen))
                result.append(i)
                break

        n = f.degree()

        if n == 1:
            result += list(map(cancel, roots_linear(f)))
        elif n == 2:
            result += list(map(cancel, roots_quadratic(f)))
        elif f.is_cyclotomic:
            result += roots_cyclotomic(f)
        elif n == 3 and cubics:
            result += roots_cubic(f)
        elif n == 4 and quartics:
            result += roots_quartic(f)
        elif n == 5 and quintics:
            result += roots_quintic(f)

        return result

    (k,), f = f.terms_gcd()

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

    coeff, f = preprocess_roots(f)

    if auto and f.get_domain().has_Ring:
        f = f.to_field()

    rescale_x = None
    translate_x = None

    result = {}

    if not f.is_ground:
        if not f.get_domain().is_Exact:
            for r in f.nroots():
                _update_dict(result, r, 1)
        elif f.degree() == 1:
            result[roots_linear(f)[0]] = 1
        elif f.degree() == 2:
            for r in roots_quadratic(f):
                _update_dict(result, r, 1)
        elif f.length() == 2:
            for r in roots_binomial(f):
                _update_dict(result, r, 1)
        else:
            _, factors = Poly(f.as_expr()).factor_list()

            if len(factors) == 1 and factors[0][1] == 1:
                if f.get_domain().is_EX:
                    res = to_rational_coeffs(f)
                    if res:
                        if res[0] is None:
                            translate_x, f = res[2:]
                        else:
                            rescale_x, f = res[1], res[-1]
                        result = roots(f)
                        if not result:
                            for root in _try_decompose(f):
                                _update_dict(result, root, 1)
                else:
                    for root in _try_decompose(f):
                        _update_dict(result, root, 1)
            else:
                for factor, k in factors:
                    for r in _try_heuristics(Poly(factor, f.gen, field=True)):
                        _update_dict(result, r, k)

    if coeff is not S.One:
        _result, result, = result, {}

        for root, k in _result.items():
            result[coeff*root] = k

    result.update(zeros)

    if filter 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[filter]
        except KeyError:
            raise ValueError("Invalid filter: %s" % filter)

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

    if predicate is not None:
        for zero in dict(result).keys():
            if not predicate(zero):
                del result[zero]
    if rescale_x:
        result1 = {}
        for k, v in result.items():
            result1[k*rescale_x] = v
        result = result1
    if translate_x:
        result1 = {}
        for k, v in result.items():
            result1[k + translate_x] = v
        result = result1

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

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

        return sorted(zeros, key=default_sort_key)
def roots ( f , * gens , * * flags ) : from sympy . polys . polytools import to_rational_coeffs flags = dict ( flags ) auto = flags . pop ( 'auto' , True ) cubics = flags . pop ( 'cubics' , True ) quartics = flags . pop ( 'quartics' , True ) quintics = flags . pop ( 'quintics' , False ) multiple = flags . pop ( 'multiple' , False ) filter = flags . pop ( 'filter' , None ) predicate = flags . pop ( 'predicate' , None ) if isinstance ( f , list ) : if gens : raise ValueError ( 'redundant generators given' ) x = Dummy ( 'x' ) poly , i = { } , len ( f ) - 1 for coeff in f : poly [ i ] , i = sympify ( coeff ) , i - 1 f = Poly ( poly , x , field = True ) else : try : f = Poly ( f , * gens , * * flags ) except GeneratorsNeeded : if multiple : return [ ] else : return { } if f . is_multivariate : raise PolynomialError ( 'multivariate polynomials are not supported' ) 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 , roots = f . decompose ( ) , [ ] for root in _try_heuristics ( factors [ 0 ] ) : roots . append ( root ) for factor in factors [ 1 : ] : previous , roots = list ( roots ) , [ ] for root in previous : g = factor - Poly ( root , f . gen ) for root in _try_heuristics ( g ) : roots . append ( root ) return roots def _try_heuristics ( f ) : """Find roots using formulas and some tricks. """ if f . is_ground : return [ ] if f . is_monomial : return [ S ( 0 ) ] * f . degree ( ) if f . length ( ) == 2 : if f . degree ( ) == 1 : return list ( map ( cancel , roots_linear ( f ) ) ) else : return roots_binomial ( f ) result = [ ] for i in [ - 1 , 1 ] : if not f . eval ( i ) : f = f . quo ( Poly ( f . gen - i , f . gen ) ) result . append ( i ) break n = f . degree ( ) if n == 1 : result += list ( map ( cancel , roots_linear ( f ) ) ) elif n == 2 : result += list ( map ( cancel , roots_quadratic ( f ) ) ) elif f . is_cyclotomic : result += roots_cyclotomic ( f ) elif n == 3 and cubics : result += roots_cubic ( f ) elif n == 4 and quartics : result += roots_quartic ( f ) elif n == 5 and quintics : result += roots_quintic ( f ) return result ( k , ) , f = f . terms_gcd ( ) if not k : zeros = { } else : zeros = { S ( 0 ) : k } coeff , f = preprocess_roots ( f ) if auto and f . get_domain ( ) . has_Ring : f = f . to_field ( ) rescale_x = None translate_x = None result = { } if not f . is_ground : if not f . get_domain ( ) . is_Exact : for r in f . nroots ( ) : _update_dict ( result , r , 1 ) elif f . degree ( ) == 1 : result [ roots_linear ( f ) [ 0 ] ] = 1 elif f . degree ( ) == 2 : for r in roots_quadratic ( f ) : _update_dict ( result , r , 1 ) elif f . length ( ) == 2 : for r in roots_binomial ( f ) : _update_dict ( result , r , 1 ) else : _ , factors = Poly ( f . as_expr ( ) ) . factor_list ( ) if len ( factors ) == 1 and factors [ 0 ] [ 1 ] == 1 : if f . get_domain ( ) . is_EX : res = to_rational_coeffs ( f ) if res : if res [ 0 ] is None : translate_x , f = res [ 2 : ] else : rescale_x , f = res [ 1 ] , res [ - 1 ] result = roots ( f ) if not result : for root in _try_decompose ( f ) : _update_dict ( result , root , 1 ) else : for root in _try_decompose ( f ) : _update_dict ( result , root , 1 ) else : for factor , k in factors : for r in _try_heuristics ( Poly ( factor , f . gen , field = True ) ) : _update_dict ( result , r , k ) if coeff is not S . One : _result , result , = result , { } for root , k in _result . items ( ) : result [ coeff * root ] = k result . update ( zeros ) if filter 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 [ filter ] except KeyError : raise ValueError ( "Invalid filter: %s" % filter ) for zero in dict ( result ) . keys ( ) : if not query ( zero ) : del result [ zero ] if predicate is not None : for zero in dict ( result ) . keys ( ) : if not predicate ( zero ) : del result [ zero ] if rescale_x : result1 = { } for k , v in result . items ( ) : result1 [ k * rescale_x ] = v result = result1 if translate_x : result1 = { } for k , v in result . items ( ) : result1 [ k + translate_x ] = v result = result1 if not multiple : return result else : zeros = [ ] for zero , k in result . items ( ) : zeros . extend ( [ zero ] * k ) return sorted ( zeros , key = default_sort_key )