def _futrig(e, **kwargs): """Helper for futrig.""" from sympy.simplify.fu import ( TR1, TR2, TR3, TR2i, TR10, L, TR10i, TR8, TR6, TR15, TR16, TR111, TR5, TRmorrie, TR11, TR14, TR22, TR12) from sympy.core.compatibility import _nodes if not e.has(TrigonometricFunction): return e if e.is_Mul: coeff, e = e.as_independent(TrigonometricFunction) else: coeff = S.One Lops = lambda x: (L(x), x.count_ops(), _nodes(x), len(x.args), x.is_Add) trigs = lambda x: x.has(TrigonometricFunction) tree = [identity, ( TR3, # canonical angles TR1, # sec-csc -> cos-sin TR12, # expand tan of sum lambda x: _eapply(factor, x, trigs), TR2, # tan-cot -> sin-cos [identity, lambda x: _eapply(_mexpand, x, trigs)], TR2i, # sin-cos ratio -> tan lambda x: _eapply(lambda i: factor(i.normal()), x, trigs), TR14, # factored identities TR5, # sin-pow -> cos_pow TR10, # sin-cos of sums -> sin-cos prod TR11, TR6, # reduce double angles and rewrite cos pows lambda x: _eapply(factor, x, trigs), TR14, # factored powers of identities [identity, lambda x: _eapply(_mexpand, x, trigs)], TRmorrie, TR10i, # sin-cos products > sin-cos of sums [identity, TR8], # sin-cos products -> sin-cos of sums [identity, lambda x: TR2i(TR2(x))], # tan -> sin-cos -> tan [ lambda x: _eapply(expand_mul, TR5(x), trigs), lambda x: _eapply( expand_mul, TR15(x), trigs)], # pos/neg powers of sin [ lambda x: _eapply(expand_mul, TR6(x), trigs), lambda x: _eapply( expand_mul, TR16(x), trigs)], # pos/neg powers of cos TR111, # tan, sin, cos to neg power -> cot, csc, sec [identity, TR2i], # sin-cos ratio to tan [identity, lambda x: _eapply( expand_mul, TR22(x), trigs)], # tan-cot to sec-csc TR1, TR2, TR2i, [identity, lambda x: _eapply( factor_terms, TR12(x), trigs)], # expand tan of sum )] e = greedy(tree, objective=Lops)(e) return coeff*e
def test_TR2i(): # just a reminder that ratios of powers only simplify if both # numerator and denominator satisfy the condition that each # has a positive base or an integer exponent; e.g. the following, # at y=-1, x=1/2 gives sqrt(2)*I != -sqrt(2)*I assert powsimp(2**x / y**x) != (2 / y)**x assert TR2i(sin(x) / cos(x)) == tan(x) assert TR2i(sin(x) * sin(y) / cos(x)) == tan(x) * sin(y) assert TR2i(1 / (sin(x) / cos(x))) == 1 / tan(x) assert TR2i(1 / (sin(x) * sin(y) / cos(x))) == 1 / tan(x) / sin(y) assert TR2i(sin(x) / 2 / (cos(x) + 1)) == sin(x) / (cos(x) + 1) / 2 assert TR2i(sin(x) / 2 / (cos(x) + 1), half=True) == tan(x / 2) / 2 assert TR2i(sin(1) / (cos(1) + 1), half=True) == tan(S.Half) assert TR2i(sin(2) / (cos(2) + 1), half=True) == tan(1) assert TR2i(sin(4) / (cos(4) + 1), half=True) == tan(2) assert TR2i(sin(5) / (cos(5) + 1), half=True) == tan(5 * S.Half) assert TR2i((cos(1) + 1) / sin(1), half=True) == 1 / tan(S.Half) assert TR2i((cos(2) + 1) / sin(2), half=True) == 1 / tan(1) assert TR2i((cos(4) + 1) / sin(4), half=True) == 1 / tan(2) assert TR2i((cos(5) + 1) / sin(5), half=True) == 1 / tan(5 * S.Half) assert TR2i((cos(1) + 1)**(-a) * sin(1)**a, half=True) == tan(S.Half)**a assert TR2i((cos(2) + 1)**(-a) * sin(2)**a, half=True) == tan(1)**a assert TR2i((cos(4) + 1)**(-a) * sin(4)**a, half=True) == (cos(4) + 1)**(-a) * sin(4)**a assert TR2i((cos(5) + 1)**(-a) * sin(5)**a, half=True) == (cos(5) + 1)**(-a) * sin(5)**a assert TR2i((cos(1) + 1)**a * sin(1)**(-a), half=True) == tan(S.Half)**(-a) assert TR2i((cos(2) + 1)**a * sin(2)**(-a), half=True) == tan(1)**(-a) assert TR2i((cos(4) + 1)**a * sin(4)**(-a), half=True) == (cos(4) + 1)**a * sin(4)**(-a) assert TR2i((cos(5) + 1)**a * sin(5)**(-a), half=True) == (cos(5) + 1)**a * sin(5)**(-a) i = symbols('i', integer=True) assert TR2i(((cos(5) + 1)**i * sin(5)**(-i)), half=True) == tan(5 * S.Half)**(-i) assert TR2i(1 / ((cos(5) + 1)**i * sin(5)**(-i)), half=True) == tan(5 * S.Half)**i
def exptrigsimp(expr): """ Simplifies exponential / trigonometric / hyperbolic functions. Examples ======== >>> from sympy import exptrigsimp, exp, cosh, sinh >>> from sympy.abc import z >>> exptrigsimp(exp(z) + exp(-z)) 2*cosh(z) >>> exptrigsimp(cosh(z) - sinh(z)) exp(-z) """ from sympy.simplify.fu import hyper_as_trig, TR2i from sympy.simplify.simplify import bottom_up def exp_trig(e): # select the better of e, and e rewritten in terms of exp or trig # functions choices = [e] if e.has(*_trigs): choices.append(e.rewrite(exp)) choices.append(e.rewrite(cos)) return min(*choices, key=count_ops) newexpr = bottom_up(expr, exp_trig) def f(rv): if not rv.is_Mul: return rv commutative_part, noncommutative_part = rv.args_cnc() # Since as_powers_dict loses order information, # if there is more than one noncommutative factor, # it should only be used to simplify the commutative part. if (len(noncommutative_part) > 1): return f(Mul(*commutative_part)) * Mul(*noncommutative_part) rvd = rv.as_powers_dict() newd = rvd.copy() def signlog(expr, sign=1): if expr is S.Exp1: return sign, 1 elif isinstance(expr, exp): return sign, expr.args[0] elif sign == 1: return signlog(-expr, sign=-1) else: return None, None ee = rvd[S.Exp1] for k in rvd: if k.is_Add and len(k.args) == 2: # k == c*(1 + sign*E**x) c = k.args[0] sign, x = signlog(k.args[1] / c) if not x: continue m = rvd[k] newd[k] -= m if ee == -x * m / 2: # sinh and cosh newd[S.Exp1] -= ee ee = 0 if sign == 1: newd[2 * c * cosh(x / 2)] += m else: newd[-2 * c * sinh(x / 2)] += m elif newd[1 - sign * S.Exp1**x] == -m: # tanh del newd[1 - sign * S.Exp1**x] if sign == 1: newd[-c / tanh(x / 2)] += m else: newd[-c * tanh(x / 2)] += m else: newd[1 + sign * S.Exp1**x] += m newd[c] += m return Mul(*[k**newd[k] for k in newd]) newexpr = bottom_up(newexpr, f) # sin/cos and sinh/cosh ratios to tan and tanh, respectively if newexpr.has(HyperbolicFunction): e, f = hyper_as_trig(newexpr) newexpr = f(TR2i(e)) if newexpr.has(TrigonometricFunction): newexpr = TR2i(newexpr) # can we ever generate an I where there was none previously? if not (newexpr.has(I) and not expr.has(I)): expr = newexpr return expr
def exptrigsimp(expr, simplify=True): """ Simplifies exponential / trigonometric / hyperbolic functions. When ``simplify`` is True (default) the expression obtained after the simplification step will be then be passed through simplify to precondition it so the final transformations will be applied. Examples ======== >>> from sympy import exptrigsimp, exp, cosh, sinh >>> from sympy.abc import z >>> exptrigsimp(exp(z) + exp(-z)) 2*cosh(z) >>> exptrigsimp(cosh(z) - sinh(z)) exp(-z) """ from sympy.simplify.fu import hyper_as_trig, TR2i from sympy.simplify.simplify import bottom_up def exp_trig(e): # select the better of e, and e rewritten in terms of exp or trig # functions choices = [e] if e.has(*_trigs): choices.append(e.rewrite(exp)) choices.append(e.rewrite(cos)) return min(*choices, key=count_ops) newexpr = bottom_up(expr, exp_trig) if simplify: newexpr = newexpr.simplify() # conversion from exp to hyperbolic ex = newexpr.atoms(exp, S.Exp1) ex = [ei for ei in ex if 1 / ei not in ex] ## sinh and cosh for ei in ex: e2 = ei**-2 if e2 in ex: a = e2.args[0] / 2 if not e2 is S.Exp1 else S.Half newexpr = newexpr.subs((e2 + 1) * ei, 2 * cosh(a)) newexpr = newexpr.subs((e2 - 1) * ei, 2 * sinh(a)) ## exp ratios to tan and tanh for ei in ex: n, d = ei - 1, ei + 1 et = n / d etinv = d / n # not 1/et or else recursion errors arise a = ei.args[0] if ei.func is exp else S.One if a.is_Mul or a is S.ImaginaryUnit: c = a.as_coefficient(I) if c: t = S.ImaginaryUnit * tan(c / 2) newexpr = newexpr.subs(etinv, 1 / t) newexpr = newexpr.subs(et, t) continue t = tanh(a / 2) newexpr = newexpr.subs(etinv, 1 / t) newexpr = newexpr.subs(et, t) # sin/cos and sinh/cosh ratios to tan and tanh, respectively if newexpr.has(HyperbolicFunction): e, f = hyper_as_trig(newexpr) newexpr = f(TR2i(e)) if newexpr.has(TrigonometricFunction): newexpr = TR2i(newexpr) # can we ever generate an I where there was none previously? if not (newexpr.has(I) and not expr.has(I)): expr = newexpr return expr