def test_frac_in(): assert frac_in(Poly((x + 1) / x * t, t), x) == (Poly(t * x + t, x), Poly(x, x)) assert frac_in((x + 1) / x * t, x) == (Poly(t * x + t, x), Poly(x, x)) assert frac_in((Poly((x + 1) / x * t, t), Poly(t + 1, t)), x) == (Poly(t * x + t, x), Poly((1 + t) * x, x)) raises(ValueError, lambda: frac_in((x + 1) / log(x) * t, x)) assert frac_in(Poly((2 + 2 * x + x * (1 + x)) / (1 + x) ** 2, t), x, cancel=True) == ( Poly(x + 2, x), Poly(x + 1, x), )
def cancel_exp(b, c, n, DE): """ Poly Risch Differential Equation - Cancellation: Hyperexponential case. Given a derivation D on k[t], n either an integer or +oo, b in k, and c in k[t] with Dt/t in k and b != 0, either raise NonElementaryIntegralException, in which case the equation Dq + b*q == c has no solution of degree at most n in k[t], or a solution q in k[t] of this equation with deg(q) <= n. """ from sympy.integrals.prde import parametric_log_deriv eta = DE.d.quo(Poly(DE.t, DE.t)).as_expr() with DecrementLevel(DE): etaa, etad = frac_in(eta, DE.t) ba, bd = frac_in(b, DE.t) A = parametric_log_deriv(ba, bd, etaa, etad, DE) if A is not None: a, m, z = A if a == 1: raise NotImplementedError("is_deriv_in_field() is required to " "solve this problem.") # if c*z*t**m == Dp for p in k<t> and q = p/(z*t**m) in k[t] and # deg(q) <= n: # return q # else: # raise NonElementaryIntegralException if c.is_zero: return c # return 0 if n < c.degree(DE.t): raise NonElementaryIntegralException q = Poly(0, DE.t) while not c.is_zero: m = c.degree(DE.t) if n < m: raise NonElementaryIntegralException # a1 = b + m*Dt/t a1 = b.as_expr() with DecrementLevel(DE): # TODO: Write a dummy function that does this idiom a1a, a1d = frac_in(a1, DE.t) a1a = a1a*etad + etaa*a1d*Poly(m, DE.t) a1d = a1d*etad a2a, a2d = frac_in(c.LC(), DE.t) sa, sd = rischDE(a1a, a1d, a2a, a2d, DE) stm = Poly(sa.as_expr()/sd.as_expr()*DE.t**m, DE.t, expand=False) q += stm n = m - 1 c -= b*stm + derivation(stm, DE) # deg(c) becomes smaller return q
def cancel_primitive(b, c, n, DE): """ Poly Risch Differential Equation - Cancellation: Primitive case. Given a derivation D on k[t], n either an integer or +oo, b in k, and c in k[t] with Dt in k and b != 0, either raise NonElementaryIntegralException, in which case the equation Dq + b*q == c has no solution of degree at most n in k[t], or a solution q in k[t] of this equation with deg(q) <= n. """ from sympy.integrals.prde import is_log_deriv_k_t_radical_in_field with DecrementLevel(DE): ba, bd = frac_in(b, DE.t) A = is_log_deriv_k_t_radical_in_field(ba, bd, DE) if A is not None: n, z = A if n == 1: # b == Dz/z raise NotImplementedError("is_deriv_in_field() is required to " " solve this problem.") # if z*c == Dp for p in k[t] and deg(p) <= n: # return p/z # else: # raise NonElementaryIntegralException if c.is_zero: return c # return 0 if n < c.degree(DE.t): raise NonElementaryIntegralException q = Poly(0, DE.t) while not c.is_zero: m = c.degree(DE.t) if n < m: raise NonElementaryIntegralException with DecrementLevel(DE): a2a, a2d = frac_in(c.LC(), DE.t) sa, sd = rischDE(ba, bd, a2a, a2d, DE) stm = Poly(sa.as_expr()/sd.as_expr()*DE.t**m, DE.t, expand=False) q += stm n = m - 1 c -= b*stm + derivation(stm, DE) return q
def prde_cancel_liouvillian(b, Q, n, DE): """ Pg, 237. """ H = [] # Why use DecrementLevel? Below line answers that: # Assuming that we can solve such problems over 'k' (not k[t]) if DE.case == 'primitive': with DecrementLevel(DE): ba, bd = frac_in(b, DE.t, field=True) for i in range(n, -1, -1): if DE.case == 'exp': # this re-checking can be avoided with DecrementLevel(DE): ba, bd = frac_in(b + i*derivation(DE.t, DE)/DE.t, DE.t, field=True) with DecrementLevel(DE): Qy = [frac_in(q.nth(i), DE.t, field=True) for q in Q] fi, Ai = param_rischDE(ba, bd, Qy, DE) fi = [Poly(fa.as_expr()/fd.as_expr(), DE.t, field=True) for fa, fd in fi] ri = len(fi) if i == n: M = Ai else: M = Ai.col_join(M.row_join(zeros(M.rows, ri))) Fi, hi = [None]*ri, [None]*ri # from eq. on top of p.238 (unnumbered) for j in range(ri): hji = fi[j]*DE.t**i hi[j] = hji # building up Sum(djn*(D(fjn*t^n) - b*fjnt^n)) Fi[j] = -(derivation(hji, DE) - b*hji) H += hi # in the next loop instead of Q it has # to be Q + Fi taking its place Q = Q + Fi return (H, M)
def prde_special_denom(a, ba, bd, G, DE, case='auto'): """ Parametric Risch Differential Equation - Special part of the denominator. case is on of {'exp', 'tan', 'primitive'} for the hyperexponential, hypertangent, and primitive cases, respectively. For the hyperexponential (resp. hypertangent) case, given a derivation D on k[t] and a in k[t], b in k<t>, and g1, ..., gm in k(t) with Dt/t in k (resp. Dt/(t**2 + 1) in k, sqrt(-1) not in k), a != 0, and gcd(a, t) == 1 (resp. gcd(a, t**2 + 1) == 1), return the tuple (A, B, GG, h) such that A, B, h in k[t], GG = [gg1, ..., ggm] in k(t)^m, and for any solution c1, ..., cm in Const(k) and q in k<t> of a*Dq + b*q == Sum(ci*gi, (i, 1, m)), r == q*h in k[t] satisfies A*Dr + B*r == Sum(ci*ggi, (i, 1, m)). For case == 'primitive', k<t> == k[t], so it returns (a, b, G, 1) in this case. """ # TODO: Merge this with the very similar special_denom() in rde.py if case == 'auto': case = DE.case if case == 'exp': p = Poly(DE.t, DE.t) elif case == 'tan': p = Poly(DE.t**2 + 1, DE.t) elif case in ['primitive', 'base']: B = ba.quo(bd) return (a, B, G, Poly(1, DE.t)) else: raise ValueError("case must be one of {'exp', 'tan', 'primitive', " "'base'}, not %s." % case) nb = order_at(ba, p, DE.t) - order_at(bd, p, DE.t) nc = min([order_at(Ga, p, DE.t) - order_at(Gd, p, DE.t) for Ga, Gd in G]) n = min(0, nc - min(0, nb)) if not nb: # Possible cancellation. if case == 'exp': dcoeff = DE.d.quo(Poly(DE.t, DE.t)) with DecrementLevel(DE): # We are guaranteed to not have problems, # because case != 'base'. alphaa, alphad = frac_in(-ba.eval(0)/bd.eval(0)/a.eval(0), DE.t) etaa, etad = frac_in(dcoeff, DE.t) A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) if A is not None: a, m, z = A if a == 1: n = min(n, m) elif case == 'tan': dcoeff = DE.d.quo(Poly(DE.t**2 + 1, DE.t)) with DecrementLevel(DE): # We are guaranteed to not have problems, # because case != 'base'. betaa, alphaa, alphad = real_imag(ba, bd*a, DE.t) betad = alphad etaa, etad = frac_in(dcoeff, DE.t) if recognize_log_derivative(2*betaa, betad, DE): A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) B = parametric_log_deriv(betaa, betad, etaa, etad, DE) if A is not None and B is not None: a, s, z = A if a == 1: n = min(n, s/2) N = max(0, -nb) pN = p**N pn = p**-n # This is 1/h A = a*pN B = ba*pN.quo(bd) + Poly(n, DE.t)*a*derivation(p, DE).quo(p)*pN G = [(Ga*pN*pn).cancel(Gd, include=True) for Ga, Gd in G] h = pn # (a*p**N, (b + n*a*Dp/p)*p**N, g1*p**(N - n), ..., gm*p**(N - n), p**-n) return (A, B, G, h)
def is_log_deriv_k_t_radical_in_field(fa, fd, DE, case='auto', z=None): """ Checks if f can be written as the logarithmic derivative of a k(t)-radical. f in k(t) can be written as the logarithmic derivative of a k(t) radical if there exist n in ZZ and u in k(t) with n, u != 0 such that n*f == Du/u. Either returns (n, u) or None, which means that f cannot be written as the logarithmic derivative of a k(t)-radical. case is one of {'primitive', 'exp', 'tan', 'auto'} for the primitive, hyperexponential, and hypertangent cases, respectively. If case it 'auto', it will attempt to determine the type of the derivation automatically. """ fa, fd = fa.cancel(fd, include=True) # f must be simple n, s = splitfactor(fd, DE) if not s.is_one: pass #return None z = z or Dummy('z') H, b = residue_reduce(fa, fd, DE, z=z) if not b: # I will have to verify, but I believe that the answer should be # None in this case. This should never happen for the # functions given when solving the parametric logarithmic # derivative problem when integration elementary functions (see # Bronstein's book, page 255), so most likely this indicates a bug. return None roots = [(i, i.real_roots()) for i, _ in H] if not all(len(j) == i.degree() and all(k.is_Rational for k in j) for i, j in roots): # If f is the logarithmic derivative of a k(t)-radical, then all the # roots of the resultant must be rational numbers. return None # [(a, i), ...], where i*log(a) is a term in the log-part of the integral # of f respolys, residues = zip(*roots) or [[], []] # Note: this might be empty, but everything below should work find in that # case (it should be the same as if it were [[1, 1]]) residueterms = [(H[j][1].subs(z, i), i) for j in xrange(len(H)) for i in residues[j]] # TODO: finish writing this and write tests p = cancel(fa.as_expr()/fd.as_expr() - residue_reduce_derivation(H, DE, z)) p = p.as_poly(DE.t) if p is None: # f - Dg will be in k[t] if f is the logarithmic derivative of a k(t)-radical return None if p.degree(DE.t) >= max(1, DE.d.degree(DE.t)): return None if case == 'auto': case = DE.case if case == 'exp': wa, wd = derivation(DE.t, DE).cancel(Poly(DE.t, DE.t), include=True) with DecrementLevel(DE): pa, pd = frac_in(p, DE.t, cancel=True) wa, wd = frac_in((wa, wd), DE.t) A = parametric_log_deriv(pa, pd, wa, wd, DE) if A is None: return None n, e, u = A u *= DE.t**e # raise NotImplementedError("The hyperexponential case is " # "not yet completely implemented for is_log_deriv_k_t_radical_in_field().") elif case == 'primitive': with DecrementLevel(DE): pa, pd = frac_in(p, DE.t) A = is_log_deriv_k_t_radical_in_field(pa, pd, DE, case='auto') if A is None: return None n, u = A elif case == 'base': # TODO: we can use more efficient residue reduction from ratint() if not fd.is_sqf or fa.degree() >= fd.degree(): # f is the logarithmic derivative in the base case if and only if # f = fa/fd, fd is square-free, deg(fa) < deg(fd), and # gcd(fa, fd) == 1. The last condition is handled by cancel() above. return None # Note: if residueterms = [], returns (1, 1) # f had better be 0 in that case. n = reduce(ilcm, [i.as_numer_denom()[1] for _, i in residueterms], S(1)) u = Mul(*[Pow(i, j*n) for i, j in residueterms]) return (n, u) elif case == 'tan': raise NotImplementedError("The hypertangent case is " "not yet implemented for is_log_deriv_k_t_radical_in_field()") elif case in ['other_linear', 'other_nonlinear']: # XXX: If these are supported by the structure theorems, change to NotImplementedError. raise ValueError("The %s case is not supported in this function." % case) else: raise ValueError("case must be one of {'primitive', 'exp', 'tan', " "'base', 'auto'}, not %s" % case) common_denom = reduce(ilcm, [i.as_numer_denom()[1] for i in [j for _, j in residueterms]] + [n], S(1)) residueterms = [(i, j*common_denom) for i, j in residueterms] m = common_denom//n assert common_denom == n*m # Verify exact division u = cancel(u**m*Mul(*[Pow(i, j) for i, j in residueterms])) return (common_denom, u)
def bound_degree(a, b, cQ, DE, case='auto', parametric=False): """ Bound on polynomial solutions. Given a derivation D on k[t] and a, b, c in k[t] with a != 0, return n in ZZ such that deg(q) <= n for any solution q in k[t] of a*Dq + b*q == c, when parametric=False, or deg(q) <= n for any solution c1, ..., cm in Const(k) and q in k[t] of a*Dq + b*q == Sum(ci*gi, (i, 1, m)) when parametric=True. For parametric=False, cQ is c, a Poly; for parametric=True, cQ is Q == [q1, ..., qm], a list of Polys. This constitutes step 3 of the outline given in the rde.py docstring. """ from sympy.integrals.prde import (parametric_log_deriv, limited_integrate, is_log_deriv_k_t_radical_in_field) # TODO: finish writing this and write tests if case == 'auto': case = DE.case da = a.degree(DE.t) db = b.degree(DE.t) # The parametric and regular cases are identical, except for this part if parametric: dc = max([i.degree(DE.t) for i in cQ]) else: dc = cQ.degree(DE.t) alpha = cancel(-b.as_poly(DE.t).LC().as_expr()/ a.as_poly(DE.t).LC().as_expr()) if case == 'base': n = max(0, dc - max(db, da - 1)) if db == da - 1 and alpha.is_Integer: n = max(0, alpha, dc - db) elif case == 'primitive': if db > da: n = max(0, dc - db) else: n = max(0, dc - da + 1) etaa, etad = frac_in(DE.d, DE.T[DE.level - 1]) t1 = DE.t with DecrementLevel(DE): alphaa, alphad = frac_in(alpha, DE.t) if db == da - 1: # if alpha == m*Dt + Dz for z in k and m in ZZ: try: (za, zd), m = limited_integrate(alphaa, alphad, [(etaa, etad)], DE) except NonElementaryIntegralException: pass else: assert len(m) == 1 n = max(n, m[0]) elif db == da: # if alpha == Dz/z for z in k*: # beta = -lc(a*Dz + b*z)/(z*lc(a)) # if beta == m*Dt + Dw for w in k and m in ZZ: # n = max(n, m) A = is_log_deriv_k_t_radical_in_field(alphaa, alphad, DE) if A is not None: aa, z = A if aa == 1: beta = -(a*derivation(z, DE).as_poly(t1) + b*z.as_poly(t1)).LC()/(z.as_expr()*a.LC()) betaa, betad = frac_in(beta, DE.t) try: (za, zd), m = limited_integrate(betaa, betad, [(etaa, etad)], DE) except NonElementaryIntegralException: pass else: assert len(m) == 1 n = max(n, m[0]) elif case == 'exp': n = max(0, dc - max(db, da)) if da == db: etaa, etad = frac_in(DE.d.quo(Poly(DE.t, DE.t)), DE.T[DE.level - 1]) with DecrementLevel(DE): alphaa, alphad = frac_in(alpha, DE.t) A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) if A is not None: # if alpha == m*Dt/t + Dz/z for z in k* and m in ZZ: # n = max(n, m) a, m, z = A if a == 1: n = max(n, m) elif case in ['tan', 'other_nonlinear']: delta = DE.d.degree(DE.t) lam = DE.d.LC() alpha = cancel(alpha/lam) n = max(0, dc - max(da + delta - 1, db)) if db == da + delta - 1 and alpha.is_Integer: n = max(0, alpha, dc - db) else: raise ValueError("case must be one of {'exp', 'tan', 'primitive', " "'other_nonlinear', 'base'}, not %s." % case) return n
def special_denom(a, ba, bd, ca, cd, DE, case='auto'): """ Special part of the denominator. case is one of {'exp', 'tan', 'primitive'} for the hyperexponential, hypertangent, and primitive cases, respectively. For the hyperexponential (resp. hypertangent) case, given a derivation D on k[t] and a in k[t], b, c, in k<t> with Dt/t in k (resp. Dt/(t**2 + 1) in k, sqrt(-1) not in k), a != 0, and gcd(a, t) == 1 (resp. gcd(a, t**2 + 1) == 1), return the quadruplet (A, B, C, 1/h) such that A, B, C, h in k[t] and for any solution q in k<t> of a*Dq + b*q == c, r = qh in k[t] satisfies A*Dr + B*r == C. For case == 'primitive', k<t> == k[t], so it returns (a, b, c, 1) in this case. This constitutes step 2 of the outline given in the rde.py docstring. """ from sympy.integrals.prde import parametric_log_deriv # TODO: finish writing this and write tests if case == 'auto': case = DE.case if case == 'exp': p = Poly(DE.t, DE.t) elif case == 'tan': p = Poly(DE.t**2 + 1, DE.t) elif case in ['primitive', 'base']: B = ba.to_field().quo(bd) C = ca.to_field().quo(cd) return (a, B, C, Poly(1, DE.t)) else: raise ValueError("case must be one of {'exp', 'tan', 'primitive', " "'base'}, not %s." % case) # assert a.div(p)[1] nb = order_at(ba, p, DE.t) - order_at(bd, p, DE.t) nc = order_at(ca, p, DE.t) - order_at(cd, p, DE.t) n = min(0, nc - min(0, nb)) if not nb: # Possible cancellation. if case == 'exp': dcoeff = DE.d.quo(Poly(DE.t, DE.t)) with DecrementLevel(DE): # We are guaranteed to not have problems, # because case != 'base'. alphaa, alphad = frac_in(-ba.eval(0)/bd.eval(0)/a.eval(0), DE.t) etaa, etad = frac_in(dcoeff, DE.t) A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) if A is not None: a, m, z = A if a == 1: n = min(n, m) else: raise NotImplementedError("Tangent case not implemented yet for " "RDE special_denom().") # if alpha == m*Dt/t + Dz/z # parametric logarithmic derivative problem # n = min(n, m) # elif case == 'tan': # alpha*sqrt(-1) + beta = (-b/a).rem(p) == -b(sqrt(-1))/a(sqrt(-1)) # eta = derivation(t, DE).quo(Poly(t**2 + 1, t)) # eta in k # if 2*beta == Dv/v for some v in k* (see pg. 176) and \ # alpha*sqrt(-1) + beta == 2*m*eta*sqrt(-1) + Dz/z: # # parametric logarithmic derivative problem # n = min(n, m) N = max(0, -nb, n - nc) pN = p**N pn = p**-n A = a*pN B = ba*pN.quo(bd) + Poly(n, DE.t)*a*derivation(p, DE).quo(p)*pN C = (ca*pN*pn).quo(cd) h = pn # (a*p**N, (b + n*a*Dp/p)*p**N, c*p**(N - n), p**-n) return (A, B, C, h)
def prde_no_cancel_b_small(b, Q, n, DE): """ Parametric Poly Risch Differential Equation - No cancellation: deg(b) small enough. Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with deg(b) < deg(D) - 1 and either D == d/dt or deg(D) >= 2, returns h1, ..., hr in k[t] and a matrix A with coefficients in Const(k) such that if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and Dq + b*q == Sum(ci*qi, (i, 1, m)) then q = Sum(dj*hj, (j, 1, r)) where d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0. """ m = len(Q) H = [Poly(0, DE.t)]*m for N in range(n, 0, -1): # [n, ..., 1] for i in range(m): si = Q[i].nth(N + DE.d.degree(DE.t) - 1)/(N*DE.d.LC()) sitn = Poly(si*DE.t**N, DE.t) H[i] = H[i] + sitn Q[i] = Q[i] - derivation(sitn, DE) - b*sitn if b.degree(DE.t) > 0: for i in range(m): si = Poly(Q[i].nth(b.degree(DE.t))/b.LC(), DE.t) H[i] = H[i] + si Q[i] = Q[i] - derivation(si, DE) - b*si if all(qi.is_zero for qi in Q): dc = -1 M = Matrix() else: dc = max([qi.degree(DE.t) for qi in Q]) M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i)) A, u = constant_system(M, zeros(dc + 1, 1), DE) c = eye(m) A = A.row_join(zeros(A.rows, m)).col_join(c.row_join(-c)) return (H, A) # else: b is in k, deg(qi) < deg(Dt) t = DE.t if DE.case != 'base': with DecrementLevel(DE): t0 = DE.t # k = k0(t0) ba, bd = frac_in(b, t0, field=True) Q0 = [frac_in(qi.TC(), t0, field=True) for qi in Q] f, B = param_rischDE(ba, bd, Q0, DE) # f = [f1, ..., fr] in k^r and B is a matrix with # m + r columns and entries in Const(k) = Const(k0) # such that Dy0 + b*y0 = Sum(ci*qi, (i, 1, m)) has # a solution y0 in k with c1, ..., cm in Const(k) # if and only y0 = Sum(dj*fj, (j, 1, r)) where # d1, ..., dr ar in Const(k) and # B*Matrix([c1, ..., cm, d1, ..., dr]) == 0. # Transform fractions (fa, fd) in f into constant # polynomials fa/fd in k[t]. # (Is there a better way?) f = [Poly(fa.as_expr()/fd.as_expr(), t, field=True) for fa, fd in f] else: # Base case. Dy == 0 for all y in k and b == 0. # Dy + b*y = Sum(ci*qi) is solvable if and only if # Sum(ci*qi) == 0 in which case the solutions are # y = d1*f1 for f1 = 1 and any d1 in Const(k) = k. f = [Poly(1, t, field=True)] # r = 1 B = Matrix([[qi.TC() for qi in Q] + [S(0)]]) # The condition for solvability is # B*Matrix([c1, ..., cm, d1]) == 0 # There are no constraints on d1. # Coefficients of t^j (j > 0) in Sum(ci*qi) must be zero. d = max([qi.degree(DE.t) for qi in Q]) if d > 0: M = Matrix(d, m, lambda i, j: Q[j].nth(i + 1)) A, _ = constant_system(M, zeros(d, 1), DE) else: # No constraints on the hj. A = Matrix(0, m, []) # Solutions of the original equation are # y = Sum(dj*fj, (j, 1, r) + Sum(ei*hi, (i, 1, m)), # where ei == ci (i = 1, ..., m), when # A*Matrix([c1, ..., cm]) == 0 and # B*Matrix([c1, ..., cm, d1, ..., dr]) == 0 # Build combined constraint matrix with m + r + m columns. r = len(f) I = eye(m) A = A.row_join(zeros(A.rows, r + m)) B = B.row_join(zeros(B.rows, m)) C = I.row_join(zeros(m, r)).row_join(-I) return f + H, A.col_join(B).col_join(C)
B = ba.quo(bd) return (a, B, G, Poly(1, DE.t)) else: raise ValueError("case must be one of {'exp', 'tan', 'primitive', " "'base'}, not %s." % case) nb = order_at(ba, p, DE.t) - order_at(bd, p, DE.t) nc = min([order_at(Ga, p, DE.t) - order_at(Gd, p, DE.t) for Ga, Gd in G]) n = min(0, nc - min(0, nb)) if not nb: # Possible cancellation. if case == 'exp': dcoeff = DE.d.quo(Poly(DE.t, DE.t)) with DecrementLevel(DE): # We are guaranteed to not have problems, # because case != 'base'. alphaa, alphad = frac_in(-ba.eval(0) / bd.eval(0) / a.eval(0), DE.t) etaa, etad = frac_in(dcoeff, DE.t) A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) if A is not None: a, m, z = A if a == 1: n = min(n, m) elif case == 'tan': dcoeff = DE.d.quo(Poly(DE.t**2 + 1, DE.t)) with DecrementLevel(DE): # We are guaranteed to not have problems, # because case != 'base'. betaa, alphaa, alphad = real_imag(ba, bd * a, DE.t) betad = alphad etaa, etad = frac_in(dcoeff, DE.t) if recognize_log_derivative(2 * betaa, betad, DE):
else: raise ValueError("case must be one of {'exp', 'tan', 'primitive', " "'base'}, not %s." % case) nb = order_at(ba, p, DE.t) - order_at(bd, p, DE.t) nc = order_at(ca, p, DE.t) - order_at(cd, p, DE.t) n = min(0, nc - min(0, nb)) if not nb: # Possible cancellation. if case == 'exp': dcoeff = DE.d.quo(Poly(DE.t, DE.t)) with DecrementLevel(DE): # We are guaranteed to not have problems, # because case != 'base'. alphaa, alphad = frac_in(-ba.eval(0) / bd.eval(0) / a.eval(0), DE.t) etaa, etad = frac_in(dcoeff, DE.t) A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) if A is not None: Q, m, z = A if Q == 1: n = min(n, m) elif case == 'tan': dcoeff = DE.d.quo(Poly(DE.t**2 + 1, DE.t)) with DecrementLevel(DE): # We are guaranteed to not have problems, # because case != 'base'. alphaa, alphad = frac_in( im(-ba.eval(sqrt(-1)) / bd.eval(sqrt(-1)) / a.eval(sqrt(-1))), DE.t) betaa, betad = frac_in(