test_heurisch.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. from sympy.concrete.summations import Sum
  2. from sympy.core.add import Add
  3. from sympy.core.function import (Derivative, Function, diff)
  4. from sympy.core.numbers import (I, Rational, pi)
  5. from sympy.core.relational import Ne
  6. from sympy.core.symbol import (Symbol, symbols)
  7. from sympy.functions.elementary.exponential import (LambertW, exp, log)
  8. from sympy.functions.elementary.hyperbolic import (asinh, cosh, sinh, tanh)
  9. from sympy.functions.elementary.miscellaneous import sqrt
  10. from sympy.functions.elementary.piecewise import Piecewise
  11. from sympy.functions.elementary.trigonometric import (acos, asin, atan, cos, sin, tan)
  12. from sympy.functions.special.bessel import (besselj, besselk, bessely, jn)
  13. from sympy.functions.special.error_functions import erf
  14. from sympy.integrals.integrals import Integral
  15. from sympy.simplify.ratsimp import ratsimp
  16. from sympy.simplify.simplify import simplify
  17. from sympy.integrals.heurisch import components, heurisch, heurisch_wrapper
  18. from sympy.testing.pytest import XFAIL, skip, slow, ON_CI
  19. from sympy.integrals.integrals import integrate
  20. x, y, z, nu = symbols('x,y,z,nu')
  21. f = Function('f')
  22. def test_components():
  23. assert components(x*y, x) == {x}
  24. assert components(1/(x + y), x) == {x}
  25. assert components(sin(x), x) == {sin(x), x}
  26. assert components(sin(x)*sqrt(log(x)), x) == \
  27. {log(x), sin(x), sqrt(log(x)), x}
  28. assert components(x*sin(exp(x)*y), x) == \
  29. {sin(y*exp(x)), x, exp(x)}
  30. assert components(x**Rational(17, 54)/sqrt(sin(x)), x) == \
  31. {sin(x), x**Rational(1, 54), sqrt(sin(x)), x}
  32. assert components(f(x), x) == \
  33. {x, f(x)}
  34. assert components(Derivative(f(x), x), x) == \
  35. {x, f(x), Derivative(f(x), x)}
  36. assert components(f(x)*diff(f(x), x), x) == \
  37. {x, f(x), Derivative(f(x), x), Derivative(f(x), x)}
  38. def test_issue_10680():
  39. assert isinstance(integrate(x**log(x**log(x**log(x))),x), Integral)
  40. def test_issue_21166():
  41. assert integrate(sin(x/sqrt(abs(x))), (x, -1, 1)) == 0
  42. def test_heurisch_polynomials():
  43. assert heurisch(1, x) == x
  44. assert heurisch(x, x) == x**2/2
  45. assert heurisch(x**17, x) == x**18/18
  46. # For coverage
  47. assert heurisch_wrapper(y, x) == y*x
  48. def test_heurisch_fractions():
  49. assert heurisch(1/x, x) == log(x)
  50. assert heurisch(1/(2 + x), x) == log(x + 2)
  51. assert heurisch(1/(x + sin(y)), x) == log(x + sin(y))
  52. # Up to a constant, where C = pi*I*Rational(5, 12), Mathematica gives identical
  53. # result in the first case. The difference is because SymPy changes
  54. # signs of expressions without any care.
  55. # XXX ^ ^ ^ is this still correct?
  56. assert heurisch(5*x**5/(
  57. 2*x**6 - 5), x) in [5*log(2*x**6 - 5) / 12, 5*log(-2*x**6 + 5) / 12]
  58. assert heurisch(5*x**5/(2*x**6 + 5), x) == 5*log(2*x**6 + 5) / 12
  59. assert heurisch(1/x**2, x) == -1/x
  60. assert heurisch(-1/x**5, x) == 1/(4*x**4)
  61. def test_heurisch_log():
  62. assert heurisch(log(x), x) == x*log(x) - x
  63. assert heurisch(log(3*x), x) == -x + x*log(3) + x*log(x)
  64. assert heurisch(log(x**2), x) in [x*log(x**2) - 2*x, 2*x*log(x) - 2*x]
  65. def test_heurisch_exp():
  66. assert heurisch(exp(x), x) == exp(x)
  67. assert heurisch(exp(-x), x) == -exp(-x)
  68. assert heurisch(exp(17*x), x) == exp(17*x) / 17
  69. assert heurisch(x*exp(x), x) == x*exp(x) - exp(x)
  70. assert heurisch(x*exp(x**2), x) == exp(x**2) / 2
  71. assert heurisch(exp(-x**2), x) is None
  72. assert heurisch(2**x, x) == 2**x/log(2)
  73. assert heurisch(x*2**x, x) == x*2**x/log(2) - 2**x*log(2)**(-2)
  74. assert heurisch(Integral(x**z*y, (y, 1, 2), (z, 2, 3)).function, x) == (x*x**z*y)/(z+1)
  75. assert heurisch(Sum(x**z, (z, 1, 2)).function, z) == x**z/log(x)
  76. # https://github.com/sympy/sympy/issues/23707
  77. anti = -exp(z)/(sqrt(x - y)*exp(z*sqrt(x - y)) - exp(z*sqrt(x - y)))
  78. assert heurisch(exp(z)*exp(-z*sqrt(x - y)), z) == anti
  79. def test_heurisch_trigonometric():
  80. assert heurisch(sin(x), x) == -cos(x)
  81. assert heurisch(pi*sin(x) + 1, x) == x - pi*cos(x)
  82. assert heurisch(cos(x), x) == sin(x)
  83. assert heurisch(tan(x), x) in [
  84. log(1 + tan(x)**2)/2,
  85. log(tan(x) + I) + I*x,
  86. log(tan(x) - I) - I*x,
  87. ]
  88. assert heurisch(sin(x)*sin(y), x) == -cos(x)*sin(y)
  89. assert heurisch(sin(x)*sin(y), y) == -cos(y)*sin(x)
  90. # gives sin(x) in answer when run via setup.py and cos(x) when run via py.test
  91. assert heurisch(sin(x)*cos(x), x) in [sin(x)**2 / 2, -cos(x)**2 / 2]
  92. assert heurisch(cos(x)/sin(x), x) == log(sin(x))
  93. assert heurisch(x*sin(7*x), x) == sin(7*x) / 49 - x*cos(7*x) / 7
  94. assert heurisch(1/pi/4 * x**2*cos(x), x) == 1/pi/4*(x**2*sin(x) -
  95. 2*sin(x) + 2*x*cos(x))
  96. assert heurisch(acos(x/4) * asin(x/4), x) == 2*x - (sqrt(16 - x**2))*asin(x/4) \
  97. + (sqrt(16 - x**2))*acos(x/4) + x*asin(x/4)*acos(x/4)
  98. assert heurisch(sin(x)/(cos(x)**2+1), x) == -atan(cos(x)) #fixes issue 13723
  99. assert heurisch(1/(cos(x)+2), x) == 2*sqrt(3)*atan(sqrt(3)*tan(x/2)/3)/3
  100. assert heurisch(2*sin(x)*cos(x)/(sin(x)**4 + 1), x) == atan(sqrt(2)*sin(x)
  101. - 1) - atan(sqrt(2)*sin(x) + 1)
  102. assert heurisch(1/cosh(x), x) == 2*atan(tanh(x/2))
  103. def test_heurisch_hyperbolic():
  104. assert heurisch(sinh(x), x) == cosh(x)
  105. assert heurisch(cosh(x), x) == sinh(x)
  106. assert heurisch(x*sinh(x), x) == x*cosh(x) - sinh(x)
  107. assert heurisch(x*cosh(x), x) == x*sinh(x) - cosh(x)
  108. assert heurisch(
  109. x*asinh(x/2), x) == x**2*asinh(x/2)/2 + asinh(x/2) - x*sqrt(4 + x**2)/4
  110. def test_heurisch_mixed():
  111. assert heurisch(sin(x)*exp(x), x) == exp(x)*sin(x)/2 - exp(x)*cos(x)/2
  112. assert heurisch(sin(x/sqrt(-x)), x) == 2*x*cos(x/sqrt(-x))/sqrt(-x) - 2*sin(x/sqrt(-x))
  113. def test_heurisch_radicals():
  114. assert heurisch(1/sqrt(x), x) == 2*sqrt(x)
  115. assert heurisch(1/sqrt(x)**3, x) == -2/sqrt(x)
  116. assert heurisch(sqrt(x)**3, x) == 2*sqrt(x)**5/5
  117. assert heurisch(sin(x)*sqrt(cos(x)), x) == -2*sqrt(cos(x))**3/3
  118. y = Symbol('y')
  119. assert heurisch(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \
  120. 2*sqrt(x)*cos(y*sqrt(x))/y
  121. assert heurisch_wrapper(sin(y*sqrt(x)), x) == Piecewise(
  122. (-2*sqrt(x)*cos(sqrt(x)*y)/y + 2*sin(sqrt(x)*y)/y**2, Ne(y, 0)),
  123. (0, True))
  124. y = Symbol('y', positive=True)
  125. assert heurisch_wrapper(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \
  126. 2*sqrt(x)*cos(y*sqrt(x))/y
  127. def test_heurisch_special():
  128. assert heurisch(erf(x), x) == x*erf(x) + exp(-x**2)/sqrt(pi)
  129. assert heurisch(exp(-x**2)*erf(x), x) == sqrt(pi)*erf(x)**2 / 4
  130. def test_heurisch_symbolic_coeffs():
  131. assert heurisch(1/(x + y), x) == log(x + y)
  132. assert heurisch(1/(x + sqrt(2)), x) == log(x + sqrt(2))
  133. assert simplify(diff(heurisch(log(x + y + z), y), y)) == log(x + y + z)
  134. def test_heurisch_symbolic_coeffs_1130():
  135. y = Symbol('y')
  136. assert heurisch_wrapper(1/(x**2 + y), x) == Piecewise(
  137. (log(x - sqrt(-y))/(2*sqrt(-y)) - log(x + sqrt(-y))/(2*sqrt(-y)),
  138. Ne(y, 0)), (-1/x, True))
  139. y = Symbol('y', positive=True)
  140. assert heurisch_wrapper(1/(x**2 + y), x) == (atan(x/sqrt(y))/sqrt(y))
  141. def test_heurisch_hacking():
  142. assert heurisch(sqrt(1 + 7*x**2), x, hints=[]) == \
  143. x*sqrt(1 + 7*x**2)/2 + sqrt(7)*asinh(sqrt(7)*x)/14
  144. assert heurisch(sqrt(1 - 7*x**2), x, hints=[]) == \
  145. x*sqrt(1 - 7*x**2)/2 + sqrt(7)*asin(sqrt(7)*x)/14
  146. assert heurisch(1/sqrt(1 + 7*x**2), x, hints=[]) == \
  147. sqrt(7)*asinh(sqrt(7)*x)/7
  148. assert heurisch(1/sqrt(1 - 7*x**2), x, hints=[]) == \
  149. sqrt(7)*asin(sqrt(7)*x)/7
  150. assert heurisch(exp(-7*x**2), x, hints=[]) == \
  151. sqrt(7*pi)*erf(sqrt(7)*x)/14
  152. assert heurisch(1/sqrt(9 - 4*x**2), x, hints=[]) == \
  153. asin(x*Rational(2, 3))/2
  154. assert heurisch(1/sqrt(9 + 4*x**2), x, hints=[]) == \
  155. asinh(x*Rational(2, 3))/2
  156. assert heurisch(1/sqrt(3*x**2-4), x, hints=[]) == \
  157. sqrt(3)*log(3*x + sqrt(3)*sqrt(3*x**2 - 4))/3
  158. def test_heurisch_function():
  159. assert heurisch(f(x), x) is None
  160. @XFAIL
  161. def test_heurisch_function_derivative():
  162. # TODO: it looks like this used to work just by coincindence and
  163. # thanks to sloppy implementation. Investigate why this used to
  164. # work at all and if support for this can be restored.
  165. df = diff(f(x), x)
  166. assert heurisch(f(x)*df, x) == f(x)**2/2
  167. assert heurisch(f(x)**2*df, x) == f(x)**3/3
  168. assert heurisch(df/f(x), x) == log(f(x))
  169. def test_heurisch_wrapper():
  170. f = 1/(y + x)
  171. assert heurisch_wrapper(f, x) == log(x + y)
  172. f = 1/(y - x)
  173. assert heurisch_wrapper(f, x) == -log(x - y)
  174. f = 1/((y - x)*(y + x))
  175. assert heurisch_wrapper(f, x) == Piecewise(
  176. (-log(x - y)/(2*y) + log(x + y)/(2*y), Ne(y, 0)), (1/x, True))
  177. # issue 6926
  178. f = sqrt(x**2/((y - x)*(y + x)))
  179. assert heurisch_wrapper(f, x) == x*sqrt(-x**2/(x**2 - y**2)) \
  180. - y**2*sqrt(-x**2/(x**2 - y**2))/x
  181. def test_issue_3609():
  182. assert heurisch(1/(x * (1 + log(x)**2)), x) == atan(log(x))
  183. ### These are examples from the Poor Man's Integrator
  184. ### http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/examples/
  185. def test_pmint_rat():
  186. # TODO: heurisch() is off by a constant: -3/4. Possibly different permutation
  187. # would give the optimal result?
  188. def drop_const(expr, x):
  189. if expr.is_Add:
  190. return Add(*[ arg for arg in expr.args if arg.has(x) ])
  191. else:
  192. return expr
  193. f = (x**7 - 24*x**4 - 4*x**2 + 8*x - 8)/(x**8 + 6*x**6 + 12*x**4 + 8*x**2)
  194. g = (4 + 8*x**2 + 6*x + 3*x**3)/(x**5 + 4*x**3 + 4*x) + log(x)
  195. assert drop_const(ratsimp(heurisch(f, x)), x) == g
  196. def test_pmint_trig():
  197. f = (x - tan(x)) / tan(x)**2 + tan(x)
  198. g = -x**2/2 - x/tan(x) + log(tan(x)**2 + 1)/2
  199. assert heurisch(f, x) == g
  200. @slow # 8 seconds on 3.4 GHz
  201. def test_pmint_logexp():
  202. if ON_CI:
  203. # See https://github.com/sympy/sympy/pull/12795
  204. skip("Too slow for CI.")
  205. f = (1 + x + x*exp(x))*(x + log(x) + exp(x) - 1)/(x + log(x) + exp(x))**2/x
  206. g = log(x + exp(x) + log(x)) + 1/(x + exp(x) + log(x))
  207. assert ratsimp(heurisch(f, x)) == g
  208. def test_pmint_erf():
  209. f = exp(-x**2)*erf(x)/(erf(x)**3 - erf(x)**2 - erf(x) + 1)
  210. g = sqrt(pi)*log(erf(x) - 1)/8 - sqrt(pi)*log(erf(x) + 1)/8 - sqrt(pi)/(4*erf(x) - 4)
  211. assert ratsimp(heurisch(f, x)) == g
  212. def test_pmint_LambertW():
  213. f = LambertW(x)
  214. g = x*LambertW(x) - x + x/LambertW(x)
  215. assert heurisch(f, x) == g
  216. def test_pmint_besselj():
  217. f = besselj(nu + 1, x)/besselj(nu, x)
  218. g = nu*log(x) - log(besselj(nu, x))
  219. assert heurisch(f, x) == g
  220. f = (nu*besselj(nu, x) - x*besselj(nu + 1, x))/x
  221. g = besselj(nu, x)
  222. assert heurisch(f, x) == g
  223. f = jn(nu + 1, x)/jn(nu, x)
  224. g = nu*log(x) - log(jn(nu, x))
  225. assert heurisch(f, x) == g
  226. @slow
  227. def test_pmint_bessel_products():
  228. # Note: Derivatives of Bessel functions have many forms.
  229. # Recurrence relations are needed for comparisons.
  230. if ON_CI:
  231. skip("Too slow for CI.")
  232. f = x*besselj(nu, x)*bessely(nu, 2*x)
  233. g = -2*x*besselj(nu, x)*bessely(nu - 1, 2*x)/3 + x*besselj(nu - 1, x)*bessely(nu, 2*x)/3
  234. assert heurisch(f, x) == g
  235. f = x*besselj(nu, x)*besselk(nu, 2*x)
  236. g = -2*x*besselj(nu, x)*besselk(nu - 1, 2*x)/5 - x*besselj(nu - 1, x)*besselk(nu, 2*x)/5
  237. assert heurisch(f, x) == g
  238. @slow # 110 seconds on 3.4 GHz
  239. def test_pmint_WrightOmega():
  240. if ON_CI:
  241. skip("Too slow for CI.")
  242. def omega(x):
  243. return LambertW(exp(x))
  244. f = (1 + omega(x) * (2 + cos(omega(x)) * (x + omega(x))))/(1 + omega(x))/(x + omega(x))
  245. g = log(x + LambertW(exp(x))) + sin(LambertW(exp(x)))
  246. assert heurisch(f, x) == g
  247. def test_RR():
  248. # Make sure the algorithm does the right thing if the ring is RR. See
  249. # issue 8685.
  250. assert heurisch(sqrt(1 + 0.25*x**2), x, hints=[]) == \
  251. 0.5*x*sqrt(0.25*x**2 + 1) + 1.0*asinh(0.5*x)
  252. # TODO: convert the rest of PMINT tests:
  253. # Airy functions
  254. # f = (x - AiryAi(x)*AiryAi(1, x)) / (x**2 - AiryAi(x)**2)
  255. # g = Rational(1,2)*ln(x + AiryAi(x)) + Rational(1,2)*ln(x - AiryAi(x))
  256. # f = x**2 * AiryAi(x)
  257. # g = -AiryAi(x) + AiryAi(1, x)*x
  258. # Whittaker functions
  259. # f = WhittakerW(mu + 1, nu, x) / (WhittakerW(mu, nu, x) * x)
  260. # g = x/2 - mu*ln(x) - ln(WhittakerW(mu, nu, x))
  261. def test_issue_22527():
  262. t, R = symbols(r't R')
  263. z = Function('z')(t)
  264. def f(x):
  265. return x/sqrt(R**2 - x**2)
  266. Uz = integrate(f(z), z)
  267. Ut = integrate(f(t), t)
  268. assert Ut == Uz.subs(z, t)