def test_hyper_as_trig(): from sympy.simplify.fu import _osborne, _osbornei eq = sinh(x)**2 + cosh(x)**2 t, f = hyper_as_trig(eq) assert f(fu(t)) == cosh(2 * x) e, f = hyper_as_trig(tanh(x + y)) assert f(TR12(e)) == (tanh(x) + tanh(y)) / (tanh(x) * tanh(y) + 1) d = Dummy() assert _osborne(sinh(x), d) == I * sin(x * d) assert _osborne(tanh(x), d) == I * tan(x * d) assert _osborne(coth(x), d) == cot(x * d) / I assert _osborne(cosh(x), d) == cos(x * d) assert _osborne(sech(x), d) == sec(x * d) assert _osborne(csch(x), d) == csc(x * d) / I for func in (sinh, cosh, tanh, coth, sech, csch): h = func(pi) assert _osbornei(_osborne(h, d), d) == h # /!\ the _osborne functions are not meant to work # in the o(i(trig, d), d) direction so we just check # that they work as they are supposed to work assert _osbornei(cos(x * y + z), y) == cosh(x + z * I) assert _osbornei(sin(x * y + z), y) == sinh(x + z * I) / I assert _osbornei(tan(x * y + z), y) == tanh(x + z * I) / I assert _osbornei(cot(x * y + z), y) == coth(x + z * I) * I assert _osbornei(sec(x * y + z), y) == sech(x + z * I) assert _osbornei(csc(x * y + z), y) == csch(x + z * I) * I
def test_hyper_as_trig(): from sympy.simplify.fu import _osborne as o, _osbornei as i, TR12 eq = sinh(x)**2 + cosh(x)**2 t, f = hyper_as_trig(eq) assert f(fu(t)) == cosh(2*x) e, f = hyper_as_trig(tanh(x + y)) assert f(TR12(e)) == (tanh(x) + tanh(y))/(tanh(x)*tanh(y) + 1) d = Dummy() assert o(sinh(x), d) == I*sin(x*d) assert o(tanh(x), d) == I*tan(x*d) assert o(coth(x), d) == cot(x*d)/I assert o(cosh(x), d) == cos(x*d) for func in (sinh, cosh, tanh, coth): h = func(pi) assert i(o(h, d), d) == h # /!\ the _osborne functions are not meant to work # in the o(i(trig, d), d) direction so we just check # that they work as they are supposed to work assert i(cos(x*y), y) == cosh(x) assert i(sin(x*y), y) == sinh(x)/I assert i(tan(x*y), y) == tanh(x)/I assert i(cot(x*y), y) == coth(x)*I assert i(sec(x*y), y) == 1/cosh(x) assert i(csc(x*y), y) == I/sinh(x)
def test_hyper_as_trig(): from sympy.simplify.fu import _osborne, _osbornei eq = sinh(x)**2 + cosh(x)**2 t, f = hyper_as_trig(eq) assert f(fu(t)) == cosh(2 * x) assert _osborne(cosh(x)) == cos(x) assert _osborne(sinh(x)) == I * sin(x) assert _osborne(tanh(x)) == I * tan(x) assert _osborne(coth(x)) == cot(x) / I assert _osbornei(cos(x)) == cosh(x) assert _osbornei(sin(x)) == sinh(x) / I assert _osbornei(tan(x)) == tanh(x) / I assert _osbornei(cot(x)) == coth(x) * I assert _osbornei(sec(x)) == 1 / cosh(x) assert _osbornei(csc(x)) == I / sinh(x)
def test_hyper_as_trig(): from sympy.simplify.fu import _osborne, _osbornei eq = sinh(x)**2 + cosh(x)**2 t, f = hyper_as_trig(eq) assert f(fu(t)) == cosh(2*x) assert _osborne(cosh(x)) == cos(x) assert _osborne(sinh(x)) == I*sin(x) assert _osborne(tanh(x)) == I*tan(x) assert _osborne(coth(x)) == cot(x)/I assert _osbornei(cos(x)) == cosh(x) assert _osbornei(sin(x)) == sinh(x)/I assert _osbornei(tan(x)) == tanh(x)/I assert _osbornei(cot(x)) == coth(x)*I assert _osbornei(sec(x)) == 1/cosh(x) assert _osbornei(csc(x)) == I/sinh(x)
def futrig(e, **kwargs): """Return simplified ``e`` using Fu-like transformations. This is not the "Fu" algorithm. This is called by default from ``trigsimp``. By default, hyperbolics subexpressions will be simplified, but this can be disabled by setting ``hyper=False``. Examples ======== >>> from sympy import trigsimp, tan, sinh, tanh >>> from sympy.simplify.trigsimp import futrig >>> from sympy.abc import x >>> trigsimp(1/tan(x)**2) tan(x)**(-2) >>> futrig(sinh(x)/tanh(x)) cosh(x) """ from sympy.simplify.fu import hyper_as_trig from sympy.simplify.simplify import bottom_up e = sympify(e) if not isinstance(e, Basic): return e if not e.args: return e old = e e = bottom_up(e, lambda x: _futrig(x, **kwargs)) if kwargs.pop('hyper', True) and e.has(HyperbolicFunction): e, f = hyper_as_trig(e) e = f(_futrig(e)) if e != old and e.is_Mul and e.args[0].is_Rational: # redistribute leading coeff on 2-arg Add e = Mul(*e.as_coeff_Mul()) return e
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): """ 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
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