def build_ideal(x, terms): """ Build generators for our ideal. Terms is an iterable with elements of the form (fn, coeff), indicating that we have a generator fn(coeff*x). If any of the terms is trigonometric, sin(x) and cos(x) are guaranteed to appear in terms. Similarly for hyperbolic functions. For tan(n*x), sin(n*x) and cos(n*x) are guaranteed. """ gens = [] I = [] y = Dummy('y') for fn, coeff in terms: for c, s, t, rel in ([cos, sin, tan, cos(x)**2 + sin(x)**2 - 1], [ cosh, sinh, tanh, cosh(x)**2 - sinh(x)**2 - 1 ]): if coeff == 1 and fn in [c, s]: I.append(rel) elif fn == t: I.append(t(coeff * x) * c(coeff * x) - s(coeff * x)) elif fn in [c, s]: cn = fn(coeff * y).expand(trig=True).subs(y, x) I.append(fn(coeff * x) - cn) return list(set(I))
def test_Function(): assert mcode(f(x, y, z)) == "f[x, y, z]" assert mcode(sin(x)**cos(x)) == "Sin[x]^Cos[x]" assert mcode(sign(x)) == "Sign[x]" assert mcode(atanh(x), user_functions={"atanh": "ArcTanh"}) == "ArcTanh[x]" assert (mcode(meijerg(((1, 1), (3, 4)), ((1, ), ()), x)) == "MeijerG[{{1, 1}, {3, 4}}, {{1}, {}}, x]") assert (mcode(hyper((1, 2, 3), (3, 4), x)) == "HypergeometricPFQ[{1, 2, 3}, {3, 4}, x]") assert mcode(Min(x, y)) == "Min[x, y]" assert mcode(Max(x, y)) == "Max[x, y]" assert mcode(Max(x, 2)) == "Max[2, x]" # issue sympy/sympy#15344 assert mcode(binomial(x, y)) == "Binomial[x, y]" assert mcode(log(x)) == "Log[x]" assert mcode(tan(x)) == "Tan[x]" assert mcode(cot(x)) == "Cot[x]" assert mcode(asin(x)) == "ArcSin[x]" assert mcode(acos(x)) == "ArcCos[x]" assert mcode(atan(x)) == "ArcTan[x]" assert mcode(sinh(x)) == "Sinh[x]" assert mcode(cosh(x)) == "Cosh[x]" assert mcode(tanh(x)) == "Tanh[x]" assert mcode(coth(x)) == "Coth[x]" assert mcode(sech(x)) == "Sech[x]" assert mcode(csch(x)) == "Csch[x]" assert mcode(erfc(x)) == "Erfc[x]" assert mcode(conjugate(x)) == "Conjugate[x]" assert mcode(re(x)) == "Re[x]" assert mcode(im(x)) == "Im[x]" assert mcode(polygamma(x, y)) == "PolyGamma[x, y]" class myfunc1(Function): @classmethod def eval(cls, x): pass class myfunc2(Function): @classmethod def eval(cls, x, y): pass pytest.raises( ValueError, lambda: mcode(myfunc1(x), user_functions={"myfunc1": ["Myfunc1"]})) assert mcode(myfunc1(x), user_functions={"myfunc1": "Myfunc1"}) == "Myfunc1[x]" assert mcode(myfunc2(x, y), user_functions={"myfunc2": [(lambda *x: False, "Myfunc2")] }) == "myfunc2[x, y]"
def test_nocache(clear_imports, monkeypatch): """Regression tests with DIOFANT_USE_CACHE=False. """ monkeypatch.setenv('DIOFANT_USE_CACHE', 'False') from diofant.core.cache import CACHE from diofant.core.symbol import Symbol from diofant.functions import sin, sqrt, exp, sinh # test that we don't use cache assert CACHE == [] x = Symbol('x') assert CACHE == [] # issue sympy/sympy#8840 (1 + x)*x # not raises # issue sympy/sympy#9413 (2*x).is_complex # not raises # see commit c459d18 sin(x + x) # not raises # see commit 53dd1eb mx = -Symbol('x', negative=False) assert mx.is_positive is not True px = 2*Symbol('x', positive=False) assert px.is_positive is not True # see commit 2eaaba2 s = 1/sqrt(x**2) y = Symbol('y') result = s.subs(sqrt(x**2), y) assert result == 1/y # problem from https://groups.google.com/forum/#!topic/sympy/LkTMQKC_BOw # see commit c459d18 a = Symbol('a', positive=True) f = exp(x*(-a - 1)) g = sinh(x) f*g # not raises
def test_nocache(clear_imports, monkeypatch): """Regression tests with DIOFANT_USE_CACHE=False. """ monkeypatch.setenv('DIOFANT_USE_CACHE', 'False') from diofant.core.cache import CACHE from diofant.core.symbol import Symbol from diofant.functions import sin, sqrt, exp, sinh # test that we don't use cache assert CACHE == [] x = Symbol('x') assert CACHE == [] # issue sympy/sympy#8840 (1 + x)*x # not raises # issue sympy/sympy#9413 (2*x).is_complex # not raises # see commit c459d18 sin(x + x) # not raises # see commit 53dd1eb mx = -Symbol('x', negative=False) assert mx.is_positive is not True px = 2*Symbol('x', positive=False) assert px.is_positive is not True # see commit 2eaaba2 s = 1/sqrt(x**2) y = Symbol('y') result = s.subs({sqrt(x**2): y}) assert result == 1/y # problem from https://groups.google.com/forum/#!topic/sympy/LkTMQKC_BOw # see commit c459d18 a = Symbol('a', positive=True) f = exp(x*(-a - 1)) g = sinh(x) f*g # not raises
def _expr_big_minus(cls, a, z, n): return -1 / sqrt(1 + 1 / z) * sinh(2 * a * asinh(sqrt(z)) + 2 * a * pi * I * n)
def _expr_big(cls, a, z, n): return -1 / sqrt(1 - 1 / z) * sinh(2 * a * acosh(sqrt(z)) + a * pi * I * (2 * n - 1))
def _expr_small_minus(cls, a, z): return -sqrt(z) / sqrt(1 + z) * sinh(2 * a * asinh(sqrt(z)))
def test_Function(): assert mcode(f(x, y, z)) == "f[x, y, z]" assert mcode(sin(x) ** cos(x)) == "Sin[x]^Cos[x]" assert mcode(sign(x)) == "Sign[x]" assert mcode(atanh(x), user_functions={"atanh": "ArcTanh"}) == "ArcTanh[x]" assert (mcode(meijerg(((1, 1), (3, 4)), ((1,), ()), x)) == "MeijerG[{{1, 1}, {3, 4}}, {{1}, {}}, x]") assert (mcode(hyper((1, 2, 3), (3, 4), x)) == "HypergeometricPFQ[{1, 2, 3}, {3, 4}, x]") assert mcode(Min(x, y)) == "Min[x, y]" assert mcode(Max(x, y)) == "Max[x, y]" assert mcode(Max(x, 2)) == "Max[2, x]" # issue sympy/sympy#15344 assert mcode(binomial(x, y)) == "Binomial[x, y]" assert mcode(log(x)) == "Log[x]" assert mcode(tan(x)) == "Tan[x]" assert mcode(cot(x)) == "Cot[x]" assert mcode(asin(x)) == "ArcSin[x]" assert mcode(acos(x)) == "ArcCos[x]" assert mcode(atan(x)) == "ArcTan[x]" assert mcode(sinh(x)) == "Sinh[x]" assert mcode(cosh(x)) == "Cosh[x]" assert mcode(tanh(x)) == "Tanh[x]" assert mcode(coth(x)) == "Coth[x]" assert mcode(sech(x)) == "Sech[x]" assert mcode(csch(x)) == "Csch[x]" assert mcode(erfc(x)) == "Erfc[x]" assert mcode(conjugate(x)) == "Conjugate[x]" assert mcode(re(x)) == "Re[x]" assert mcode(im(x)) == "Im[x]" assert mcode(polygamma(x, y)) == "PolyGamma[x, y]" assert mcode(factorial(x)) == "Factorial[x]" assert mcode(factorial2(x)) == "Factorial2[x]" assert mcode(rf(x, y)) == "Pochhammer[x, y]" assert mcode(gamma(x)) == "Gamma[x]" assert mcode(zeta(x)) == "Zeta[x]" assert mcode(asinh(x)) == "ArcSinh[x]" assert mcode(Heaviside(x)) == "UnitStep[x]" assert mcode(fibonacci(x)) == "Fibonacci[x]" assert mcode(polylog(x, y)) == "PolyLog[x, y]" assert mcode(atanh(x)) == "ArcTanh[x]" class myfunc1(Function): @classmethod def eval(cls, x): pass class myfunc2(Function): @classmethod def eval(cls, x, y): pass pytest.raises(ValueError, lambda: mcode(myfunc1(x), user_functions={"myfunc1": ["Myfunc1"]})) assert mcode(myfunc1(x), user_functions={"myfunc1": "Myfunc1"}) == "Myfunc1[x]" assert mcode(myfunc2(x, y), user_functions={"myfunc2": [(lambda *x: False, "Myfunc2")]}) == "myfunc2[x, y]"
def _trigpats(): global _trigpat a, b, c = symbols('a b c', cls=Wild) d = Wild('d', commutative=False) # for the simplifications like sinh/cosh -> tanh: # DO NOT REORDER THE FIRST 14 since these are assumed to be in this # order in _match_div_rewrite. matchers_division = ( (a * sin(b)**c / cos(b)**c, a * tan(b)**c, sin(b), cos(b)), (a * tan(b)**c * cos(b)**c, a * sin(b)**c, sin(b), cos(b)), (a * cot(b)**c * sin(b)**c, a * cos(b)**c, sin(b), cos(b)), (a * tan(b)**c / sin(b)**c, a / cos(b)**c, sin(b), cos(b)), (a * cot(b)**c / cos(b)**c, a / sin(b)**c, sin(b), cos(b)), (a * cot(b)**c * tan(b)**c, a, sin(b), cos(b)), (a * (cos(b) + 1)**c * (cos(b) - 1)**c, a * (-sin(b)**2)**c, cos(b) + 1, cos(b) - 1), (a * (sin(b) + 1)**c * (sin(b) - 1)**c, a * (-cos(b)**2)**c, sin(b) + 1, sin(b) - 1), (a * sinh(b)**c / cosh(b)**c, a * tanh(b)**c, S.One, S.One), (a * tanh(b)**c * cosh(b)**c, a * sinh(b)**c, S.One, S.One), (a * coth(b)**c * sinh(b)**c, a * cosh(b)**c, S.One, S.One), (a * tanh(b)**c / sinh(b)**c, a / cosh(b)**c, S.One, S.One), (a * coth(b)**c / cosh(b)**c, a / sinh(b)**c, S.One, S.One), (a * coth(b)**c * tanh(b)**c, a, S.One, S.One), (c * (tanh(a) + tanh(b)) / (1 + tanh(a) * tanh(b)), tanh(a + b) * c, S.One, S.One), ) matchers_add = ( (c * sin(a) * cos(b) + c * cos(a) * sin(b) + d, sin(a + b) * c + d), (c * cos(a) * cos(b) - c * sin(a) * sin(b) + d, cos(a + b) * c + d), (c * sin(a) * cos(b) - c * cos(a) * sin(b) + d, sin(a - b) * c + d), (c * cos(a) * cos(b) + c * sin(a) * sin(b) + d, cos(a - b) * c + d), (c * sinh(a) * cosh(b) + c * sinh(b) * cosh(a) + d, sinh(a + b) * c + d), (c * cosh(a) * cosh(b) + c * sinh(a) * sinh(b) + d, cosh(a + b) * c + d), ) # for cos(x)**2 + sin(x)**2 -> 1 matchers_identity = ( (a * sin(b)**2, a - a * cos(b)**2), (a * tan(b)**2, a * (1 / cos(b))**2 - a), (a * cot(b)**2, a * (1 / sin(b))**2 - a), (a * sin(b + c), a * (sin(b) * cos(c) + sin(c) * cos(b))), (a * cos(b + c), a * (cos(b) * cos(c) - sin(b) * sin(c))), (a * tan(b + c), a * ((tan(b) + tan(c)) / (1 - tan(b) * tan(c)))), (a * sinh(b)**2, a * cosh(b)**2 - a), (a * tanh(b)**2, a - a * (1 / cosh(b))**2), (a * coth(b)**2, a + a * (1 / sinh(b))**2), (a * sinh(b + c), a * (sinh(b) * cosh(c) + sinh(c) * cosh(b))), (a * cosh(b + c), a * (cosh(b) * cosh(c) + sinh(b) * sinh(c))), (a * tanh(b + c), a * ((tanh(b) + tanh(c)) / (1 + tanh(b) * tanh(c)))), ) # Reduce any lingering artifacts, such as sin(x)**2 changing # to 1-cos(x)**2 when sin(x)**2 was "simpler" artifacts = ( (a - a * cos(b)**2 + c, a * sin(b)**2 + c, cos), (a - a * (1 / cos(b))**2 + c, -a * tan(b)**2 + c, cos), (a - a * (1 / sin(b))**2 + c, -a * cot(b)**2 + c, sin), (a - a * cosh(b)**2 + c, -a * sinh(b)**2 + c, cosh), (a - a * (1 / cosh(b))**2 + c, a * tanh(b)**2 + c, cosh), (a + a * (1 / sinh(b))**2 + c, a * coth(b)**2 + c, sinh), # same as above but with noncommutative prefactor (a * d - a * d * cos(b)**2 + c, a * d * sin(b)**2 + c, cos), (a * d - a * d * (1 / cos(b))**2 + c, -a * d * tan(b)**2 + c, cos), (a * d - a * d * (1 / sin(b))**2 + c, -a * d * cot(b)**2 + c, sin), (a * d - a * d * cosh(b)**2 + c, -a * d * sinh(b)**2 + c, cosh), (a * d - a * d * (1 / cosh(b))**2 + c, a * d * tanh(b)**2 + c, cosh), (a * d + a * d * (1 / sinh(b))**2 + c, a * d * coth(b)**2 + c, sinh), ) _trigpat = (a, b, c, d, matchers_division, matchers_add, matchers_identity, artifacts) return _trigpat
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 diofant import exptrigsimp, exp, cosh, sinh >>> from diofant.abc import z >>> exptrigsimp(exp(z) + exp(-z)) 2*cosh(z) >>> exptrigsimp(cosh(z) - sinh(z)) E**(-z) """ from diofant.simplify.fu import hyper_as_trig, TR2i from diofant.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 = {a for a in newexpr.atoms(Pow) if a.base is S.Exp1} | newexpr.atoms(S.Exp1) if ex: ex0 = {list(ex)[0]} ex = [ei for ei in ex if 1 / ei not in ex] if not ex: ex = ex0 # sinh and cosh for ei in ex: a = ei.exp if ei is not S.Exp1 else S.One newexpr = newexpr.subs(ei + 1 / ei, 2 * cosh(a)) newexpr = newexpr.subs(ei - 1 / ei, 2 * sinh(a)) e2 = ei**-2 if e2 in ex: a = e2.exp / 2 if e2 is not 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.exp if ei.is_Pow and ei.base is S.Exp1 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