test_heurisch.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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 Eq, 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.logic.boolalg import And
  16. from sympy.matrices import Matrix
  17. from sympy.simplify.ratsimp import ratsimp
  18. from sympy.simplify.simplify import simplify
  19. from sympy.integrals.heurisch import components, heurisch, heurisch_wrapper
  20. from sympy.testing.pytest import XFAIL, slow
  21. from sympy.integrals.integrals import integrate
  22. from sympy import S
  23. x, y, z, nu = symbols('x,y,z,nu')
  24. f = Function('f')
  25. def test_components():
  26. assert components(x*y, x) == {x}
  27. assert components(1/(x + y), x) == {x}
  28. assert components(sin(x), x) == {sin(x), x}
  29. assert components(sin(x)*sqrt(log(x)), x) == \
  30. {log(x), sin(x), sqrt(log(x)), x}
  31. assert components(x*sin(exp(x)*y), x) == \
  32. {sin(y*exp(x)), x, exp(x)}
  33. assert components(x**Rational(17, 54)/sqrt(sin(x)), x) == \
  34. {sin(x), x**Rational(1, 54), sqrt(sin(x)), x}
  35. assert components(f(x), x) == \
  36. {x, f(x)}
  37. assert components(Derivative(f(x), x), x) == \
  38. {x, f(x), Derivative(f(x), x)}
  39. assert components(f(x)*diff(f(x), x), x) == \
  40. {x, f(x), Derivative(f(x), x), Derivative(f(x), x)}
  41. def test_issue_10680():
  42. assert isinstance(integrate(x**log(x**log(x**log(x))),x), Integral)
  43. def test_issue_21166():
  44. assert integrate(sin(x/sqrt(abs(x))), (x, -1, 1)) == 0
  45. def test_heurisch_polynomials():
  46. assert heurisch(1, x) == x
  47. assert heurisch(x, x) == x**2/2
  48. assert heurisch(x**17, x) == x**18/18
  49. # For coverage
  50. assert heurisch_wrapper(y, x) == y*x
  51. def test_heurisch_fractions():
  52. assert heurisch(1/x, x) == log(x)
  53. assert heurisch(1/(2 + x), x) == log(x + 2)
  54. assert heurisch(1/(x + sin(y)), x) == log(x + sin(y))
  55. # Up to a constant, where C = pi*I*Rational(5, 12), Mathematica gives identical
  56. # result in the first case. The difference is because SymPy changes
  57. # signs of expressions without any care.
  58. # XXX ^ ^ ^ is this still correct?
  59. assert heurisch(5*x**5/(
  60. 2*x**6 - 5), x) in [5*log(2*x**6 - 5) / 12, 5*log(-2*x**6 + 5) / 12]
  61. assert heurisch(5*x**5/(2*x**6 + 5), x) == 5*log(2*x**6 + 5) / 12
  62. assert heurisch(1/x**2, x) == -1/x
  63. assert heurisch(-1/x**5, x) == 1/(4*x**4)
  64. def test_heurisch_log():
  65. assert heurisch(log(x), x) == x*log(x) - x
  66. assert heurisch(log(3*x), x) == -x + x*log(3) + x*log(x)
  67. assert heurisch(log(x**2), x) in [x*log(x**2) - 2*x, 2*x*log(x) - 2*x]
  68. def test_heurisch_exp():
  69. assert heurisch(exp(x), x) == exp(x)
  70. assert heurisch(exp(-x), x) == -exp(-x)
  71. assert heurisch(exp(17*x), x) == exp(17*x) / 17
  72. assert heurisch(x*exp(x), x) == x*exp(x) - exp(x)
  73. assert heurisch(x*exp(x**2), x) == exp(x**2) / 2
  74. assert heurisch(exp(-x**2), x) is None
  75. assert heurisch(2**x, x) == 2**x/log(2)
  76. assert heurisch(x*2**x, x) == x*2**x/log(2) - 2**x*log(2)**(-2)
  77. assert heurisch(Integral(x**z*y, (y, 1, 2), (z, 2, 3)).function, x) == (x*x**z*y)/(z+1)
  78. assert heurisch(Sum(x**z, (z, 1, 2)).function, z) == x**z/log(x)
  79. # https://github.com/sympy/sympy/issues/23707
  80. anti = -exp(z)/(sqrt(x - y)*exp(z*sqrt(x - y)) - exp(z*sqrt(x - y)))
  81. assert heurisch(exp(z)*exp(-z*sqrt(x - y)), z) == anti
  82. def test_heurisch_trigonometric():
  83. assert heurisch(sin(x), x) == -cos(x)
  84. assert heurisch(pi*sin(x) + 1, x) == x - pi*cos(x)
  85. assert heurisch(cos(x), x) == sin(x)
  86. assert heurisch(tan(x), x) in [
  87. log(1 + tan(x)**2)/2,
  88. log(tan(x) + I) + I*x,
  89. log(tan(x) - I) - I*x,
  90. ]
  91. assert heurisch(sin(x)*sin(y), x) == -cos(x)*sin(y)
  92. assert heurisch(sin(x)*sin(y), y) == -cos(y)*sin(x)
  93. # gives sin(x) in answer when run via setup.py and cos(x) when run via py.test
  94. assert heurisch(sin(x)*cos(x), x) in [sin(x)**2 / 2, -cos(x)**2 / 2]
  95. assert heurisch(cos(x)/sin(x), x) == log(sin(x))
  96. assert heurisch(x*sin(7*x), x) == sin(7*x) / 49 - x*cos(7*x) / 7
  97. assert heurisch(1/pi/4 * x**2*cos(x), x) == 1/pi/4*(x**2*sin(x) -
  98. 2*sin(x) + 2*x*cos(x))
  99. assert heurisch(acos(x/4) * asin(x/4), x) == 2*x - (sqrt(16 - x**2))*asin(x/4) \
  100. + (sqrt(16 - x**2))*acos(x/4) + x*asin(x/4)*acos(x/4)
  101. assert heurisch(sin(x)/(cos(x)**2+1), x) == -atan(cos(x)) #fixes issue 13723
  102. assert heurisch(1/(cos(x)+2), x) == 2*sqrt(3)*atan(sqrt(3)*tan(x/2)/3)/3
  103. assert heurisch(2*sin(x)*cos(x)/(sin(x)**4 + 1), x) == atan(sqrt(2)*sin(x)
  104. - 1) - atan(sqrt(2)*sin(x) + 1)
  105. assert heurisch(1/cosh(x), x) == 2*atan(tanh(x/2))
  106. def test_heurisch_hyperbolic():
  107. assert heurisch(sinh(x), x) == cosh(x)
  108. assert heurisch(cosh(x), x) == sinh(x)
  109. assert heurisch(x*sinh(x), x) == x*cosh(x) - sinh(x)
  110. assert heurisch(x*cosh(x), x) == x*sinh(x) - cosh(x)
  111. assert heurisch(
  112. x*asinh(x/2), x) == x**2*asinh(x/2)/2 + asinh(x/2) - x*sqrt(4 + x**2)/4
  113. def test_heurisch_mixed():
  114. assert heurisch(sin(x)*exp(x), x) == exp(x)*sin(x)/2 - exp(x)*cos(x)/2
  115. assert heurisch(sin(x/sqrt(-x)), x) == 2*x*cos(x/sqrt(-x))/sqrt(-x) - 2*sin(x/sqrt(-x))
  116. def test_heurisch_radicals():
  117. assert heurisch(1/sqrt(x), x) == 2*sqrt(x)
  118. assert heurisch(1/sqrt(x)**3, x) == -2/sqrt(x)
  119. assert heurisch(sqrt(x)**3, x) == 2*sqrt(x)**5/5
  120. assert heurisch(sin(x)*sqrt(cos(x)), x) == -2*sqrt(cos(x))**3/3
  121. y = Symbol('y')
  122. assert heurisch(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \
  123. 2*sqrt(x)*cos(y*sqrt(x))/y
  124. assert heurisch_wrapper(sin(y*sqrt(x)), x) == Piecewise(
  125. (-2*sqrt(x)*cos(sqrt(x)*y)/y + 2*sin(sqrt(x)*y)/y**2, Ne(y, 0)),
  126. (0, True))
  127. y = Symbol('y', positive=True)
  128. assert heurisch_wrapper(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \
  129. 2*sqrt(x)*cos(y*sqrt(x))/y
  130. def test_heurisch_special():
  131. assert heurisch(erf(x), x) == x*erf(x) + exp(-x**2)/sqrt(pi)
  132. assert heurisch(exp(-x**2)*erf(x), x) == sqrt(pi)*erf(x)**2 / 4
  133. def test_heurisch_symbolic_coeffs():
  134. assert heurisch(1/(x + y), x) == log(x + y)
  135. assert heurisch(1/(x + sqrt(2)), x) == log(x + sqrt(2))
  136. assert simplify(diff(heurisch(log(x + y + z), y), y)) == log(x + y + z)
  137. def test_heurisch_symbolic_coeffs_1130():
  138. y = Symbol('y')
  139. assert heurisch_wrapper(1/(x**2 + y), x) == Piecewise(
  140. (log(x - sqrt(-y))/(2*sqrt(-y)) - log(x + sqrt(-y))/(2*sqrt(-y)),
  141. Ne(y, 0)), (-1/x, True))
  142. y = Symbol('y', positive=True)
  143. assert heurisch_wrapper(1/(x**2 + y), x) == (atan(x/sqrt(y))/sqrt(y))
  144. def test_heurisch_hacking():
  145. assert heurisch(sqrt(1 + 7*x**2), x, hints=[]) == \
  146. x*sqrt(1 + 7*x**2)/2 + sqrt(7)*asinh(sqrt(7)*x)/14
  147. assert heurisch(sqrt(1 - 7*x**2), x, hints=[]) == \
  148. x*sqrt(1 - 7*x**2)/2 + sqrt(7)*asin(sqrt(7)*x)/14
  149. assert heurisch(1/sqrt(1 + 7*x**2), x, hints=[]) == \
  150. sqrt(7)*asinh(sqrt(7)*x)/7
  151. assert heurisch(1/sqrt(1 - 7*x**2), x, hints=[]) == \
  152. sqrt(7)*asin(sqrt(7)*x)/7
  153. assert heurisch(exp(-7*x**2), x, hints=[]) == \
  154. sqrt(7*pi)*erf(sqrt(7)*x)/14
  155. assert heurisch(1/sqrt(9 - 4*x**2), x, hints=[]) == \
  156. asin(x*Rational(2, 3))/2
  157. assert heurisch(1/sqrt(9 + 4*x**2), x, hints=[]) == \
  158. asinh(x*Rational(2, 3))/2
  159. assert heurisch(1/sqrt(3*x**2-4), x, hints=[]) == \
  160. sqrt(3)*log(3*x + sqrt(3)*sqrt(3*x**2 - 4))/3
  161. def test_heurisch_function():
  162. assert heurisch(f(x), x) is None
  163. @XFAIL
  164. def test_heurisch_function_derivative():
  165. # TODO: it looks like this used to work just by coincindence and
  166. # thanks to sloppy implementation. Investigate why this used to
  167. # work at all and if support for this can be restored.
  168. df = diff(f(x), x)
  169. assert heurisch(f(x)*df, x) == f(x)**2/2
  170. assert heurisch(f(x)**2*df, x) == f(x)**3/3
  171. assert heurisch(df/f(x), x) == log(f(x))
  172. def test_heurisch_wrapper():
  173. f = 1/(y + x)
  174. assert heurisch_wrapper(f, x) == log(x + y)
  175. f = 1/(y - x)
  176. assert heurisch_wrapper(f, x) == -log(x - y)
  177. f = 1/((y - x)*(y + x))
  178. assert heurisch_wrapper(f, x) == Piecewise(
  179. (-log(x - y)/(2*y) + log(x + y)/(2*y), Ne(y, 0)), (1/x, True))
  180. # issue 6926
  181. f = sqrt(x**2/((y - x)*(y + x)))
  182. assert heurisch_wrapper(f, x) == x*sqrt(-x**2/(x**2 - y**2)) \
  183. - y**2*sqrt(-x**2/(x**2 - y**2))/x
  184. def test_issue_3609():
  185. assert heurisch(1/(x * (1 + log(x)**2)), x) == atan(log(x))
  186. ### These are examples from the Poor Man's Integrator
  187. ### http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/examples/
  188. def test_pmint_rat():
  189. # TODO: heurisch() is off by a constant: -3/4. Possibly different permutation
  190. # would give the optimal result?
  191. def drop_const(expr, x):
  192. if expr.is_Add:
  193. return Add(*[ arg for arg in expr.args if arg.has(x) ])
  194. else:
  195. return expr
  196. f = (x**7 - 24*x**4 - 4*x**2 + 8*x - 8)/(x**8 + 6*x**6 + 12*x**4 + 8*x**2)
  197. g = (4 + 8*x**2 + 6*x + 3*x**3)/(x**5 + 4*x**3 + 4*x) + log(x)
  198. assert drop_const(ratsimp(heurisch(f, x)), x) == g
  199. def test_pmint_trig():
  200. f = (x - tan(x)) / tan(x)**2 + tan(x)
  201. g = -x**2/2 - x/tan(x) + log(tan(x)**2 + 1)/2
  202. assert heurisch(f, x) == g
  203. def test_pmint_logexp():
  204. f = (1 + x + x*exp(x))*(x + log(x) + exp(x) - 1)/(x + log(x) + exp(x))**2/x
  205. g = log(x + exp(x) + log(x)) + 1/(x + exp(x) + log(x))
  206. assert ratsimp(heurisch(f, x)) == g
  207. def test_pmint_erf():
  208. f = exp(-x**2)*erf(x)/(erf(x)**3 - erf(x)**2 - erf(x) + 1)
  209. g = sqrt(pi)*log(erf(x) - 1)/8 - sqrt(pi)*log(erf(x) + 1)/8 - sqrt(pi)/(4*erf(x) - 4)
  210. assert ratsimp(heurisch(f, x)) == g
  211. def test_pmint_LambertW():
  212. f = LambertW(x)
  213. g = x*LambertW(x) - x + x/LambertW(x)
  214. assert heurisch(f, x) == g
  215. def test_pmint_besselj():
  216. f = besselj(nu + 1, x)/besselj(nu, x)
  217. g = nu*log(x) - log(besselj(nu, x))
  218. assert heurisch(f, x) == g
  219. f = (nu*besselj(nu, x) - x*besselj(nu + 1, x))/x
  220. g = besselj(nu, x)
  221. assert heurisch(f, x) == g
  222. f = jn(nu + 1, x)/jn(nu, x)
  223. g = nu*log(x) - log(jn(nu, x))
  224. assert heurisch(f, x) == g
  225. @slow
  226. def test_pmint_bessel_products():
  227. f = x*besselj(nu, x)*bessely(nu, 2*x)
  228. g = -2*x*besselj(nu, x)*bessely(nu - 1, 2*x)/3 + x*besselj(nu - 1, x)*bessely(nu, 2*x)/3
  229. assert heurisch(f, x) == g
  230. f = x*besselj(nu, x)*besselk(nu, 2*x)
  231. g = -2*x*besselj(nu, x)*besselk(nu - 1, 2*x)/5 - x*besselj(nu - 1, x)*besselk(nu, 2*x)/5
  232. assert heurisch(f, x) == g
  233. def test_pmint_WrightOmega():
  234. def omega(x):
  235. return LambertW(exp(x))
  236. f = (1 + omega(x) * (2 + cos(omega(x)) * (x + omega(x))))/(1 + omega(x))/(x + omega(x))
  237. g = log(x + LambertW(exp(x))) + sin(LambertW(exp(x)))
  238. assert heurisch(f, x) == g
  239. def test_RR():
  240. # Make sure the algorithm does the right thing if the ring is RR. See
  241. # issue 8685.
  242. assert heurisch(sqrt(1 + 0.25*x**2), x, hints=[]) == \
  243. 0.5*x*sqrt(0.25*x**2 + 1) + 1.0*asinh(0.5*x)
  244. # TODO: convert the rest of PMINT tests:
  245. # Airy functions
  246. # f = (x - AiryAi(x)*AiryAi(1, x)) / (x**2 - AiryAi(x)**2)
  247. # g = Rational(1,2)*ln(x + AiryAi(x)) + Rational(1,2)*ln(x - AiryAi(x))
  248. # f = x**2 * AiryAi(x)
  249. # g = -AiryAi(x) + AiryAi(1, x)*x
  250. # Whittaker functions
  251. # f = WhittakerW(mu + 1, nu, x) / (WhittakerW(mu, nu, x) * x)
  252. # g = x/2 - mu*ln(x) - ln(WhittakerW(mu, nu, x))
  253. def test_issue_22527():
  254. t, R = symbols(r't R')
  255. z = Function('z')(t)
  256. def f(x):
  257. return x/sqrt(R**2 - x**2)
  258. Uz = integrate(f(z), z)
  259. Ut = integrate(f(t), t)
  260. assert Ut == Uz.subs(z, t)
  261. def test_heurisch_complex_erf_issue_26338():
  262. r = symbols('r', real=True)
  263. a = sqrt(pi)*erf((1 + I)/2)/2
  264. assert integrate(exp(-I*r**2/2), (r, 0, 1)) == a - I*a
  265. a = exp(-x**2/(2*(2 - I)**2))
  266. assert heurisch(a, x, hints=[]) is None # None, not a wrong soln
  267. a = exp(-r**2/(2*(2 - I)**2))
  268. assert heurisch(a, r, hints=[]) is None
  269. a = sqrt(pi)*erf((1 + I)/2)/2
  270. assert integrate(exp(-I*x**2/2), (x, 0, 1)) == a - I*a
  271. def test_issue_15498():
  272. Z0 = Function('Z0')
  273. k01, k10, t, s= symbols('k01 k10 t s', real=True, positive=True)
  274. m = Matrix([[exp(-k10*t)]])
  275. _83 = Rational(83, 100) # 0.83 works, too
  276. [a, b, c, d, e, f, g] = [100, 0.5, _83, 50, 0.6, 2, 120]
  277. AIF_btf = a*(d*e*(1 - exp(-(t - b)/e)) + f*g*(1 - exp(-(t - b)/g)))
  278. AIF_atf = a*(d*e*exp(-(t - b)/e)*(exp((c - b)/e) - 1
  279. ) + f*g*exp(-(t - b)/g)*(exp((c - b)/g) - 1))
  280. AIF_sym = Piecewise((0, t < b), (AIF_btf, And(b <= t, t < c)), (AIF_atf, c <= t))
  281. aif_eq = Eq(Z0(t), AIF_sym)
  282. f_vec = Matrix([[k01*Z0(t)]])
  283. integrand = m*m.subs(t, s)**-1*f_vec.subs(aif_eq.lhs, aif_eq.rhs).subs(t, s)
  284. solution = integrate(integrand[0], (s, 0, t))
  285. assert solution is not None # does not hang and takes less than 10 s
  286. @slow
  287. def test_heurisch_issue_26930():
  288. integrand = x**Rational(4, 3)*log(x)
  289. anti = 3*x**(S(7)/3)*log(x)/7 - 9*x**(S(7)/3)/49
  290. assert heurisch(integrand, x) == anti
  291. assert integrate(integrand, x) == anti
  292. assert integrate(integrand, (x, 0, 1)) == -S(9)/49
  293. def test_heurisch_issue_26922():
  294. a, b, x = symbols("a, b, x", real=True, positive=True)
  295. C = symbols("C", real=True)
  296. i1 = -C*x*exp(-a*x**2 - sqrt(b)*x)
  297. i2 = C*x*exp(-a*x**2 + sqrt(b)*x)
  298. i = Integral(i1, x) + Integral(i2, x)
  299. res = (
  300. -C*exp(-a*x**2)*exp(sqrt(b)*x)/(2*a)
  301. + C*exp(-a*x**2)*exp(-sqrt(b)*x)/(2*a)
  302. + sqrt(pi)*C*sqrt(b)*exp(b/(4*a))*erf(sqrt(a)*x - sqrt(b)/(2*sqrt(a)))/(4*a**(S(3)/2))
  303. + sqrt(pi)*C*sqrt(b)*exp(b/(4*a))*erf(sqrt(a)*x + sqrt(b)/(2*sqrt(a)))/(4*a**(S(3)/2))
  304. )
  305. assert i.doit(heurisch=False).expand() == res