(eq, func, order, match)
return Eq(f(x), series)
r"""
    Gives a power series solution to a second order homogeneous differential
    equation with polynomial coefficients at an ordinary point. A homogenous
    differential equation is of the form

    .. math :: P(x)\frac{d^2y}{dx^2} + Q(x)\frac{dy}{dx} + R(x) = 0

    For simplicity it is assumed that `P(x)`, `Q(x)` and `R(x)` are polynomials,
    it is sufficient that `\frac{Q(x)}{P(x)}` and `\frac{R(x)}{P(x)}` exists at
    `x0`. A recurrence relation is obtained by substituting `y` as `\sum_{n=0}^\infty anx^n`,
    in the differential equation, and equating the nth term. Using this relation
    various terms can be generated.


    Examples
    ========

    >>> from sympy import dsolve, Function, pprint
    >>> from sympy.abc import x, y
    >>> f = Function("f")
    >>> eq = f(x).diff(x, 2) + f(x)
    >>> pprint(dsolve(eq, hint='2nd_power_series_ordinary'))
              / 4    2    \        /   2    \
              |x    x     |        |  x     |    / 6\
    f(x) = C2*|-- - -- + 1| + C1*x*|- -- + 1| + O\x /
              \24   2     /        \  6     /


    References
    ==========
    - http://tutorial.math.lamar.edu/Classes/DE/SeriesSolutions.aspx
    - George E. Simmons, "Differential Equations with Applications and
      Historical Notes", p.p 176 - 184
r"""
    Gives a power series solution to a second order homogeneous differential
    equation with polynomial coefficients at an ordinary point. A homogenous
    differential equation is of the form
r Gives a power series solution to a second order homogeneous differential equation with polynomial coefficients at an ordinary point . A homogenous differential equation is of the form
def ode_2nd_power_series_ordinary(eq, func, order, match):
    r"""
    Gives a power series solution to a second order homogeneous differential
    equation with polynomial coefficients at an ordinary point. A homogenous
    differential equation is of the form

    .. math :: P(x)\frac{d^2y}{dx^2} + Q(x)\frac{dy}{dx} + R(x) = 0

    For simplicity it is assumed that `P(x)`, `Q(x)` and `R(x)` are polynomials,
    it is sufficient that `\frac{Q(x)}{P(x)}` and `\frac{R(x)}{P(x)}` exists at
    `x0`. A recurrence relation is obtained by substituting `y` as `\sum_{n=0}^\infty anx^n`,
    in the differential equation, and equating the nth term. Using this relation
    various terms can be generated.


    Examples
    ========

    >>> from sympy import dsolve, Function, pprint
    >>> from sympy.abc import x, y
    >>> f = Function("f")
    >>> eq = f(x).diff(x, 2) + f(x)
    >>> pprint(dsolve(eq, hint='2nd_power_series_ordinary'))
              / 4    2    \        /   2    \
              |x    x     |        |  x     |    / 6\
    f(x) = C2*|-- - -- + 1| + C1*x*|- -- + 1| + O\x /
              \24   2     /        \  6     /


    References
    ==========
    - http://tutorial.math.lamar.edu/Classes/DE/SeriesSolutions.aspx
    - George E. Simmons, "Differential Equations with Applications and
      Historical Notes", p.p 176 - 184

    """
    x = func.args[0]
    f = func.func
    C0, C1 = get_numbered_constants(eq, num=2)
    n = Dummy("n")
    s = Wild("s")
    k = Wild("k", exclude=[x])
    x0 = match.get('x0')
    terms = match.get('terms', 5)
    p = match[match['a3']]
    q = match[match['b3']]
    r = match[match['c3']]
    seriesdict = {}
    recurr = Function("r")

    # Generating the recurrence relation which works this way
    # a] For the second order term the summation begins at n = 2. The coefficient
    # p is multiplied with an*(n - 1)*(n - 2)*x**n-2 and a substitution is made such that
    # the exponent of x becomes n.
    # For example, if p is x, then the second degree recurrence term is
    # an*(n - 1)*(n - 2)*x**n-1, substituting (n - 1) as n, it transforms to
    # an+1*n*(n - 1)*x**n.
    # A similar process is done with the first order and zeroth order term.

    coefflist = [(recurr(n), r), (n*recurr(n), q), (n*(n - 1)*recurr(n), p)]
    for index, coeff in enumerate(coefflist):
        if coeff[1]:
            f2 = powsimp(expand((coeff[1]*(x - x0)**(n - index)).subs(x, x + x0)))
            if f2.is_Add:
                addargs = f2.args
            else:
                addargs = [f2]
            for arg in addargs:
                powm = arg.match(s*x**k)
                term = coeff[0]*powm[s]
                if not powm[k].is_Symbol:
                    term = term.subs(n, n - powm[k].as_independent(n)[0])
                startind = powm[k].subs(n, index)
                # Seeing if the startterm can be reduced further.
                # If it vanishes for n lesser than startind, it is
                # equal to summation from n.
                if startind:
                    for i in reversed(range(startind)):
                        if not term.subs(n, i):
                            seriesdict[term] = i
                        else:
                            seriesdict[term] = i + 1
                            break
                else:
                    seriesdict[term] = S(0)

    # Stripping of terms so that the sum starts with the same number.
    teq = S(0)
    suminit = seriesdict.values()
    rkeys = seriesdict.keys()
    req = Add(*rkeys)
    if any(suminit):
        maxval = max(suminit)
        for term in seriesdict:
            val = seriesdict[term]
            if val != maxval:
                for i in range(val, maxval):
                    teq += term.subs(n, val)

    finaldict = {}
    if teq:
        fargs = teq.atoms(AppliedUndef)
        if len(fargs) == 1:
            finaldict[fargs.pop()] = 0
        else:
            maxf = max(fargs, key = lambda x: x.args[0])
            sol = solve(teq, maxf)
            if isinstance(sol, list):
                sol = sol[0]
            finaldict[maxf] = sol

    # Finding the recurrence relation in terms of the largest term.
    fargs = req.atoms(AppliedUndef)
    maxf = max(fargs, key = lambda x: x.args[0])
    minf = min(fargs, key = lambda x: x.args[0])
    if minf.args[0].is_Symbol:
        startiter = 0
    else:
        startiter = -minf.args[0].as_independent(n)[0]
    lhs = maxf
    rhs =  solve(req, maxf)
    if isinstance(rhs, list):
        rhs = rhs[0]

    # Checking how many values are already present
    tcounter = len([t for t in finaldict.values() if t])

    for count in range(tcounter, terms - 3):  # Assuming c0 and c1 to be arbitrary
    #while tcounter < terms - 2:  # Assuming c0 and c1 to be arbitrary
        check = rhs.subs(n, startiter)
        nlhs = lhs.subs(n, startiter)
        nrhs = check.subs(finaldict)
        finaldict[nlhs] = nrhs
        startiter += 1

    # Post processing
    series = C0 + C1*(x - x0)
    for term in finaldict:
        if finaldict[term]:
            fact = term.args[0]
            series += (finaldict[term].subs([(recurr(0), C0), (recurr(1), C1)])*(
                x - x0)**fact)
    series = collect(expand_mul(series), [C0, C1]) + Order(x**terms)
    return Eq(f(x), series)
def ode_2nd_power_series_ordinary ( eq , func , order , match ) : x = func . args [ 0 ] f = func . func C0 , C1 = get_numbered_constants ( eq , num = 2 ) n = Dummy ( "n" ) s = Wild ( "s" ) k = Wild ( "k" , exclude = [ x ] ) x0 = match . get ( 'x0' ) terms = match . get ( 'terms' , 5 ) p = match [ match [ 'a3' ] ] q = match [ match [ 'b3' ] ] r = match [ match [ 'c3' ] ] seriesdict = { } recurr = Function ( "r" ) # Generating the recurrence relation which works this way # a] For the second order term the summation begins at n = 2. The coefficient # p is multiplied with an*(n - 1)*(n - 2)*x**n-2 and a substitution is made such that # the exponent of x becomes n. # For example, if p is x, then the second degree recurrence term is # an*(n - 1)*(n - 2)*x**n-1, substituting (n - 1) as n, it transforms to # an+1*n*(n - 1)*x**n. # A similar process is done with the first order and zeroth order term. coefflist = [ ( recurr ( n ) , r ) , ( n * recurr ( n ) , q ) , ( n * ( n - 1 ) * recurr ( n ) , p ) ] for index , coeff in enumerate ( coefflist ) : if coeff [ 1 ] : f2 = powsimp ( expand ( ( coeff [ 1 ] * ( x - x0 ) ** ( n - index ) ) . subs ( x , x + x0 ) ) ) if f2 . is_Add : addargs = f2 . args else : addargs = [ f2 ] for arg in addargs : powm = arg . match ( s * x ** k ) term = coeff [ 0 ] * powm [ s ] if not powm [ k ] . is_Symbol : term = term . subs ( n , n - powm [ k ] . as_independent ( n ) [ 0 ] ) startind = powm [ k ] . subs ( n , index ) # Seeing if the startterm can be reduced further. # If it vanishes for n lesser than startind, it is # equal to summation from n. if startind : for i in reversed ( range ( startind ) ) : if not term . subs ( n , i ) : seriesdict [ term ] = i else : seriesdict [ term ] = i + 1 break else : seriesdict [ term ] = S ( 0 ) # Stripping of terms so that the sum starts with the same number. teq = S ( 0 ) suminit = seriesdict . values ( ) rkeys = seriesdict . keys ( ) req = Add ( * rkeys ) if any ( suminit ) : maxval = max ( suminit ) for term in seriesdict : val = seriesdict [ term ] if val != maxval : for i in range ( val , maxval ) : teq += term . subs ( n , val ) finaldict = { } if teq : fargs = teq . atoms ( AppliedUndef ) if len ( fargs ) == 1 : finaldict [ fargs . pop ( ) ] = 0 else : maxf = max ( fargs , key = lambda x : x . args [ 0 ] ) sol = solve ( teq , maxf ) if isinstance ( sol , list ) : sol = sol [ 0 ] finaldict [ maxf ] = sol # Finding the recurrence relation in terms of the largest term. fargs = req . atoms ( AppliedUndef ) maxf = max ( fargs , key = lambda x : x . args [ 0 ] ) minf = min ( fargs , key = lambda x : x . args [ 0 ] ) if minf . args [ 0 ] . is_Symbol : startiter = 0 else : startiter = - minf . args [ 0 ] . as_independent ( n ) [ 0 ] lhs = maxf rhs = solve ( req , maxf ) if isinstance ( rhs , list ) : rhs = rhs [ 0 ] # Checking how many values are already present tcounter = len ( [ t for t in finaldict . values ( ) if t ] ) for count in range ( tcounter , terms - 3 ) : # Assuming c0 and c1 to be arbitrary #while tcounter < terms - 2:  # Assuming c0 and c1 to be arbitrary check = rhs . subs ( n , startiter ) nlhs = lhs . subs ( n , startiter ) nrhs = check . subs ( finaldict ) finaldict [ nlhs ] = nrhs startiter += 1 # Post processing series = C0 + C1 * ( x - x0 ) for term in finaldict : if finaldict [ term ] : fact = term . args [ 0 ] series += ( finaldict [ term ] . subs ( [ ( recurr ( 0 ) , C0 ) , ( recurr ( 1 ) , C1 ) ] ) * ( x - x0 ) ** fact ) series = collect ( expand_mul ( series ) , [ C0 , C1 ] ) + Order ( x ** terms ) return Eq ( f ( x ) , series )