def solve_aux_eq(a, x, m, ybar):
    p = Function('p')
    auxeq = numer((p(x).diff(x, 2) + 2*ybar*p(x).diff(x) + (ybar.diff(x) + ybar**2 - a)*p(x)).together())
    psyms = get_numbered_constants(auxeq, m)
    if type(psyms) != tuple:
        psyms = (psyms, )
    psol = x**m
    for i in range(m):
        psol += psyms[i]*x**i
    if m != 0:
        return psol, solve(auxeq.subs(p(x), psol).doit().expand(), psyms, dict=True), True
    else:
        cf = auxeq.subs(p(x), psol).doit().expand()
        return S(1), cf, cf == 0
Exemple #2
0
def get_sol_2F1_hypergeometric(eq, func, match_object):
    x = func.args[0]
    from sympy.simplify.hyperexpand import hyperexpand
    from sympy.polys.polytools import factor
    C0, C1 = get_numbered_constants(eq, num=2)
    a = match_object['a']
    b = match_object['b']
    c = match_object['c']
    A = match_object['A']

    sol = None

    if c.is_integer == False:
        sol = C0 * hyper([a, b], [c], x) + C1 * hyper([a - c + 1, b - c + 1],
                                                      [2 - c], x) * x**(1 - c)
    elif c == 1:
        y2 = Integral(
            exp(Integral((-(a + b + 1) * x + c) / (x**2 - x), x)) /
            (hyperexpand(hyper([a, b], [c], x))**2), x) * hyper([a, b], [c], x)
        sol = C0 * hyper([a, b], [c], x) + C1 * y2
    elif (c - a - b).is_integer == False:
        sol = C0 * hyper([a, b], [1 + a + b - c], 1 - x) + C1 * hyper(
            [c - a, c - b], [1 + c - a - b], 1 - x) * (1 - x)**(c - a - b)

    if sol:
        # applying transformation in the solution
        subs = match_object['mobius']
        dtdx = simplify(1 / (subs.diff(x)))
        _B = ((a + b + 1) * x - c).subs(x, subs) * dtdx
        _B = factor(_B + ((x**2 - x).subs(x, subs)) * (dtdx.diff(x) * dtdx))
        _A = factor((x**2 - x).subs(x, subs) * (dtdx**2))
        e = exp(logcombine(Integral(cancel(_B / (2 * _A)), x), force=True))
        sol = sol.subs(x, match_object['mobius'])
        sol = sol.subs(x, x**match_object['k'])
        e = e.subs(x, x**match_object['k'])

        if not A.is_zero:
            e1 = Integral(A / 2, x)
            e1 = exp(logcombine(e1, force=True))
            sol = cancel((e / e1) * x**((-match_object['k'] + 1) / 2)) * sol
            sol = Eq(func, sol)
            return sol

        sol = cancel((e) * x**((-match_object['k'] + 1) / 2)) * sol
        sol = Eq(func, sol)
    return sol
Exemple #3
0
def test_get_numbered_constants():
    with raises(ValueError):
        get_numbered_constants(None)
Exemple #4
0
def test_issue_15056():
    t = Symbol('t')
    C3 = Symbol('C3')
    assert get_numbered_constants(Symbol('C1') * Function('C2')(t)) == C3
Exemple #5
0
def _get_euler_characteristic_eq_sols(eq, func, match_obj):
    r"""
    Returns the solution of homogeneous part of the linear euler ODE and
    the list of roots of characteristic equation.

    The parameter ``match_obj`` is a dict of order:coeff terms, where order is the order
    of the derivative on each term, and coeff is the coefficient of that derivative.

    """
    x = func.args[0]
    f = func.func

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

    for i in match_obj:
        if i >= 0:
            chareq += (match_obj[i] * diff(x**symbol, x, i) *
                       x**-symbol).expand()

    chareq = Poly(chareq, symbol)
    chareqroots = [rootof(chareq, k) for k in range(chareq.degree())]
    collectterms = []

    # 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.Zero
    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)))
                collectterms = [(i, reroot, imroot)] + collectterms

    gsol = Eq(f(x), gsol)

    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)
    return gsol, gensols
def find_riccati_sol(eq, log=False):
    """
    Finds and returns all rational solutions to a Riccati Differential Equation.
    """

    # Step 0 :Match the equation
    w = list(eq.atoms(Derivative))[0].args[0]
    x = list(w.free_symbols)[0]
    eq = eq.expand().collect(w)
    cf = eq.coeff(w.diff(x))
    eq = Add(*map(lambda x: cancel(x/cf), eq.args)).collect(w)
    b0, b1, b2 = match_riccati(eq, w, x)

    # Step 1 : Convert to Normal Form
    a = -b0*b2 + b1**2/4 - b1.diff(x)/2 + 3*b2.diff(x)**2/(4*b2**2) + b1*b2.diff(x)/(2*b2) - b2.diff(x, 2)/(2*b2)
    a_t = cancel(a.together())

    # Step 2
    presol = []

    # Step 3 : "a" is 0
    if a_t == 0:
        presol.append(1/(x + get_numbered_constants(eq)))

    # Step 4 : "a" is a non-zero constant
    elif a_t.is_complex:
        presol.append([sqrt(a), -sqrt(a)])

    # Step 5 : Find poles and valuation at infinity
    poles = find_poles(a_t, x)
    poles, muls = list(poles.keys()), list(poles.values())
    val_inf = val_at_inf(a_t, x)

    if log:
        print("Simplified Equation", eq)
        print("b0, b1, b2", b0, b1, b2)
        print("a", a)
        print("a_t", a_t)
        print("Constant Solutions", presol)
        print("Poles, Muls, val_inf", poles, muls, val_inf)

    if len(poles) and b2 != 0:
        # Check necessary conditions
        if val_inf%2 != 0 or not all(map(lambda mul: (mul == 1 or (mul%2 == 0 and mul >= 2)), muls)):
            raise ValueError("Rational Solution doesn't exist")

        # Step 6
        # Construct c-vectors for each singular point
        c = construct_c(a, x, poles, muls)

        # Construct d vectors for each singular point
        d = construct_d(a, x, val_inf)
        if log:
            print("C", c)
            print("D", d)

        # Step 7 : Iterate over all possible combinations and return solutions
        for it in range(2**(len(poles) + 1)):
            choice = list(map(lambda x: int(x), bin(it)[2:].zfill(len(poles) + 1)))
            # Step 8 and 9 : Compute m and ybar
            m, ybar = compute_degree(x, poles, choice, c, d, -val_inf//2)
            if log:
                print("M", m)
                print("Ybar", ybar)
            # Step 10 : Check if m is non-negative integer
            if m.is_real and m >= 0 and m.is_integer:
                # Step 11 : Find polynomial solutions of degree m for the auxiliary equation
                psol, coeffs, exists = solve_aux_eq(a, x, m, ybar)
                if log:
                    print("Psol, coeffs, exists", psol, coeffs, exists)
                # Step 12 : If valid polynomial solution exists, append solution.
                if exists:
                    if psol == 1 and coeffs == 0:
                        presol.append(ybar)
                    elif len(coeffs):
                        psol = psol.subs(coeffs[0])
                        presol.append(ybar + psol.diff(x)/psol)
    # Step 15 : Transform the solutions of the equation in normal form
    sol = list(map(lambda y: -y/b2 - b2.diff(x)/(2*b2**2) - b1/(2*b2), presol))
    return sol