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
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
def test_get_numbered_constants(): with raises(ValueError): get_numbered_constants(None)
def test_issue_15056(): t = Symbol('t') C3 = Symbol('C3') assert get_numbered_constants(Symbol('C1') * Function('C2')(t)) == C3
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