(eq, func, order, match, returns='sol')
r"""
    Solves an `n`\th order linear homogeneous variable-coefficient
    Cauchy-Euler equidimensional ordinary differential equation.

    This is an equation with form `0 = a_0 f(x) + a_1 x f'(x) + a_2 x^2 f''(x)
    \cdots`.

    These equations can be solved in a general manner, by substituting
    solutions of the form `f(x) = x^r`, and deriving a characteristic equation
    for `r`.  When there are repeated roots, we include extra terms of the
    form `C_{r k} \ln^k(x) x^r`, where `C_{r k}` is an arbitrary integration
    constant, `r` is a root of the characteristic equation, and `k` ranges
    over the multiplicity of `r`.  In the cases where the roots are complex,
    solutions of the form `C_1 x^a \sin(b \log(x)) + C_2 x^a \cos(b \log(x))`
    are returned, based on expansions with Eulers formula.  The general
    solution is the sum of the terms found.  If SymPy cannot find exact roots
    to the characteristic equation, a
    :py:class:`~sympy.polys.rootoftools.RootOf` instance will be returned
    instead.

    >>> from sympy import Function, dsolve, Eq
    >>> from sympy.abc import x
    >>> f = Function('f')
    >>> dsolve(4*x**2*f(x).diff(x, 2) + f(x), f(x),
    ... hint='nth_linear_euler_eq_homogeneous')
    ... # doctest: +NORMALIZE_WHITESPACE
        f(x) == sqrt(x)*(C1 + C2*log(x))

    Note that because this method does not involve integration, there is no
    ``nth_linear_euler_eq_homogeneous_Integral`` hint.

    The following is for internal use:

    - ``returns = 'sol'`` returns the solution to the ODE.
    - ``returns = 'list'`` returns a list of linearly independent solutions,
      corresponding to the fundamental solution set, for use with non
      homogeneous solution methods like variation of parameters and
      undetermined coefficients.  Note that, though the solutions should be
      linearly independent, this function does not explicitly check that.  You
      can do ``assert simplify(wronskian(sollist)) != 0`` to check for linear
      independence.  Also, ``assert len(sollist) == order`` will need to pass.
    - ``returns = 'both'``, return a dictionary ``{'sol': <solution to ODE>,
      'list': <list of linearly independent solutions>}``.

    Examples
    ========

    >>> from sympy import Function, dsolve, pprint
    >>> from sympy.abc import x
    >>> f = Function('f')
    >>> eq = f(x).diff(x, 2)*x**2 - 4*f(x).diff(x)*x + 6*f(x)
    >>> pprint(dsolve(eq, f(x),
    ... hint='nth_linear_euler_eq_homogeneous'))
            2
    f(x) = x *(C1 + C2*x)

    References
    ==========

    - http://en.wikipedia.org/wiki/Cauchy%E2%80%93Euler_equation
    - C. Bender & S. Orszag, "Advanced Mathematical Methods for Scientists and
      Engineers", Springer 1999, pp. 12

    # indirect doctest
r"""
    Solves an `n`\th order linear homogeneous variable-coefficient
    Cauchy-Euler equidimensional ordinary differential equation.
r Solves an n \ th order linear homogeneous variable - coefficient Cauchy - Euler equidimensional ordinary differential equation .
def ode_nth_linear_euler_eq_homogeneous(eq, func, order, match, returns='sol'):
    r"""
    Solves an `n`\th order linear homogeneous variable-coefficient
    Cauchy-Euler equidimensional ordinary differential equation.

    This is an equation with form `0 = a_0 f(x) + a_1 x f'(x) + a_2 x^2 f''(x)
    \cdots`.

    These equations can be solved in a general manner, by substituting
    solutions of the form `f(x) = x^r`, and deriving a characteristic equation
    for `r`.  When there are repeated roots, we include extra terms of the
    form `C_{r k} \ln^k(x) x^r`, where `C_{r k}` is an arbitrary integration
    constant, `r` is a root of the characteristic equation, and `k` ranges
    over the multiplicity of `r`.  In the cases where the roots are complex,
    solutions of the form `C_1 x^a \sin(b \log(x)) + C_2 x^a \cos(b \log(x))`
    are returned, based on expansions with Eulers formula.  The general
    solution is the sum of the terms found.  If SymPy cannot find exact roots
    to the characteristic equation, a
    :py:class:`~sympy.polys.rootoftools.RootOf` instance will be returned
    instead.

    >>> from sympy import Function, dsolve, Eq
    >>> from sympy.abc import x
    >>> f = Function('f')
    >>> dsolve(4*x**2*f(x).diff(x, 2) + f(x), f(x),
    ... hint='nth_linear_euler_eq_homogeneous')
    ... # doctest: +NORMALIZE_WHITESPACE
        f(x) == sqrt(x)*(C1 + C2*log(x))

    Note that because this method does not involve integration, there is no
    ``nth_linear_euler_eq_homogeneous_Integral`` hint.

    The following is for internal use:

    - ``returns = 'sol'`` returns the solution to the ODE.
    - ``returns = 'list'`` returns a list of linearly independent solutions,
      corresponding to the fundamental solution set, for use with non
      homogeneous solution methods like variation of parameters and
      undetermined coefficients.  Note that, though the solutions should be
      linearly independent, this function does not explicitly check that.  You
      can do ``assert simplify(wronskian(sollist)) != 0`` to check for linear
      independence.  Also, ``assert len(sollist) == order`` will need to pass.
    - ``returns = 'both'``, return a dictionary ``{'sol': <solution to ODE>,
      'list': <list of linearly independent solutions>}``.

    Examples
    ========

    >>> from sympy import Function, dsolve, pprint
    >>> from sympy.abc import x
    >>> f = Function('f')
    >>> eq = f(x).diff(x, 2)*x**2 - 4*f(x).diff(x)*x + 6*f(x)
    >>> pprint(dsolve(eq, f(x),
    ... hint='nth_linear_euler_eq_homogeneous'))
            2
    f(x) = x *(C1 + C2*x)

    References
    ==========

    - http://en.wikipedia.org/wiki/Cauchy%E2%80%93Euler_equation
    - C. Bender & S. Orszag, "Advanced Mathematical Methods for Scientists and
      Engineers", Springer 1999, pp. 12

    # indirect doctest

    """
    global collectterms
    collectterms = []

    x = func.args[0]
    f = func.func
    r = match

    # First, set up characteristic equation.
    chareq, symbol = S.Zero, Dummy('x')

    for i in r.keys():
        if not isinstance(i, str) and i >= 0:
            chareq += (r[i]*diff(x**symbol, x, i)*x**-symbol).expand()

    chareq = Poly(chareq, symbol)
    chareqroots = [RootOf(chareq, k) for k in xrange(chareq.degree())]

    # A generator of constants
    constants = list(get_numbered_constants(eq, num=chareq.degree()*2))
    constants.reverse()

    # Create a dict root: multiplicity or charroots
    charroots = defaultdict(int)
    for root in chareqroots:
        charroots[root] += 1
    gsol = S(0)
    # We need keep track of terms so we can run collect() at the end.
    # This is necessary for constantsimp to work properly.
    ln = log
    for root, multiplicity in charroots.items():
        for i in range(multiplicity):
            if isinstance(root, RootOf):
                gsol += (x**root) * constants.pop()
                if multiplicity != 1:
                    raise ValueError("Value should be 1")
                collectterms = [(0, root, 0)] + collectterms
            elif root.is_real:
                gsol += ln(x)**i*(x**root) * constants.pop()
                collectterms = [(i, root, 0)] + collectterms
            else:
                reroot = re(root)
                imroot = im(root)
                gsol += ln(x)**i * (x**reroot) * (
                    constants.pop() * sin(abs(imroot)*ln(x))
                    + constants.pop() * cos(imroot*ln(x)))
                # Preserve ordering (multiplicity, real part, imaginary part)
                # It will be assumed implicitly when constructing
                # fundamental solution sets.
                collectterms = [(i, reroot, imroot)] + collectterms
    if returns == 'sol':
        return Eq(f(x), gsol)
    elif returns in ('list' 'both'):
        # HOW TO TEST THIS CODE? (dsolve does not pass 'returns' through)
        # Create a list of (hopefully) linearly independent solutions
        gensols = []
        # Keep track of when to use sin or cos for nonzero imroot
        for i, reroot, imroot in collectterms:
            if imroot == 0:
                gensols.append(ln(x)**i*x**reroot)
            else:
                sin_form = ln(x)**i*x**reroot*sin(abs(imroot)*ln(x))
                if sin_form in gensols:
                    cos_form = ln(x)**i*x**reroot*cos(imroot*ln(x))
                    gensols.append(cos_form)
                else:
                    gensols.append(sin_form)
        if returns == 'list':
            return gensols
        else:
            return {'sol': Eq(f(x), gsol), 'list': gensols}
    else:
        raise ValueError('Unknown value for key "returns".')
def ode_nth_linear_euler_eq_homogeneous ( eq , func , order , match , returns = 'sol' ) : global collectterms collectterms = [ ] x = func . args [ 0 ] f = func . func r = match # First, set up characteristic equation. chareq , symbol = S . Zero , Dummy ( 'x' ) for i in r . keys ( ) : if not isinstance ( i , str ) and i >= 0 : chareq += ( r [ i ] * diff ( x ** symbol , x , i ) * x ** - symbol ) . expand ( ) chareq = Poly ( chareq , symbol ) chareqroots = [ RootOf ( chareq , k ) for k in xrange ( chareq . degree ( ) ) ] # A generator of constants constants = list ( get_numbered_constants ( eq , num = chareq . degree ( ) * 2 ) ) constants . reverse ( ) # Create a dict root: multiplicity or charroots charroots = defaultdict ( int ) for root in chareqroots : charroots [ root ] += 1 gsol = S ( 0 ) # We need keep track of terms so we can run collect() at the end. # This is necessary for constantsimp to work properly. ln = log for root , multiplicity in charroots . items ( ) : for i in range ( multiplicity ) : if isinstance ( root , RootOf ) : gsol += ( x ** root ) * constants . pop ( ) if multiplicity != 1 : raise ValueError ( "Value should be 1" ) collectterms = [ ( 0 , root , 0 ) ] + collectterms elif root . is_real : gsol += ln ( x ) ** i * ( x ** root ) * constants . pop ( ) collectterms = [ ( i , root , 0 ) ] + collectterms else : reroot = re ( root ) imroot = im ( root ) gsol += ln ( x ) ** i * ( x ** reroot ) * ( constants . pop ( ) * sin ( abs ( imroot ) * ln ( x ) ) + constants . pop ( ) * cos ( imroot * ln ( x ) ) ) # Preserve ordering (multiplicity, real part, imaginary part) # It will be assumed implicitly when constructing # fundamental solution sets. collectterms = [ ( i , reroot , imroot ) ] + collectterms if returns == 'sol' : return Eq ( f ( x ) , gsol ) elif returns in ( 'list' 'both' ) : # HOW TO TEST THIS CODE? (dsolve does not pass 'returns' through) # Create a list of (hopefully) linearly independent solutions gensols = [ ] # Keep track of when to use sin or cos for nonzero imroot for i , reroot , imroot in collectterms : if imroot == 0 : gensols . append ( ln ( x ) ** i * x ** reroot ) else : sin_form = ln ( x ) ** i * x ** reroot * sin ( abs ( imroot ) * ln ( x ) ) if sin_form in gensols : cos_form = ln ( x ) ** i * x ** reroot * cos ( imroot * ln ( x ) ) gensols . append ( cos_form ) else : gensols . append ( sin_form ) if returns == 'list' : return gensols else : return { 'sol' : Eq ( f ( x ) , gsol ) , 'list' : gensols } else : raise ValueError ( 'Unknown value for key "returns".' )