manualintegrate.py 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695
  1. """Integration method that emulates by-hand techniques.
  2. This module also provides functionality to get the steps used to evaluate a
  3. particular integral, in the ``integral_steps`` function. This will return
  4. nested namedtuples representing the integration rules used. The
  5. ``manualintegrate`` function computes the integral using those steps given
  6. an integrand; given the steps, ``_manualintegrate`` will evaluate them.
  7. The integrator can be extended with new heuristics and evaluation
  8. techniques. To do so, write a function that accepts an ``IntegralInfo``
  9. object and returns either a namedtuple representing a rule or
  10. ``None``. Then, write another function that accepts the namedtuple's fields
  11. and returns the antiderivative, and decorate it with
  12. ``@evaluates(namedtuple_type)``. If the new technique requires a new
  13. match, add the key and call to the antiderivative function to integral_steps.
  14. To enable simple substitutions, add the match to find_substitutions.
  15. """
  16. from typing import Dict as tDict, Optional
  17. from collections import namedtuple, defaultdict
  18. from collections.abc import Mapping
  19. from functools import reduce
  20. from sympy.core.add import Add
  21. from sympy.core.cache import cacheit
  22. from sympy.core.containers import Dict
  23. from sympy.core.expr import Expr
  24. from sympy.core.function import Derivative
  25. from sympy.core.logic import fuzzy_not
  26. from sympy.core.mul import Mul
  27. from sympy.core.numbers import Integer, Number, E
  28. from sympy.core.power import Pow
  29. from sympy.core.relational import Eq, Ne, Gt, Lt
  30. from sympy.core.singleton import S
  31. from sympy.core.symbol import Dummy, Symbol, Wild
  32. from sympy.functions.elementary.complexes import Abs
  33. from sympy.functions.elementary.exponential import exp, log
  34. from sympy.functions.elementary.hyperbolic import (cosh, sinh, acosh, asinh,
  35. acoth, atanh)
  36. from sympy.functions.elementary.miscellaneous import sqrt
  37. from sympy.functions.elementary.piecewise import Piecewise
  38. from sympy.functions.elementary.trigonometric import (TrigonometricFunction,
  39. cos, sin, tan, cot, csc, sec, acos, asin, atan, acot, acsc, asec)
  40. from sympy.functions.special.delta_functions import Heaviside
  41. from sympy.functions.special.error_functions import (erf, erfi, fresnelc,
  42. fresnels, Ci, Chi, Si, Shi, Ei, li)
  43. from sympy.functions.special.gamma_functions import uppergamma
  44. from sympy.functions.special.elliptic_integrals import elliptic_e, elliptic_f
  45. from sympy.functions.special.polynomials import (chebyshevt, chebyshevu,
  46. legendre, hermite, laguerre, assoc_laguerre, gegenbauer, jacobi,
  47. OrthogonalPolynomial)
  48. from sympy.functions.special.zeta_functions import polylog
  49. from .integrals import Integral
  50. from sympy.logic.boolalg import And
  51. from sympy.ntheory.factor_ import divisors
  52. from sympy.polys.polytools import degree
  53. from sympy.simplify.radsimp import fraction
  54. from sympy.simplify.simplify import simplify
  55. from sympy.solvers.solvers import solve
  56. from sympy.strategies.core import switch, do_one, null_safe, condition
  57. from sympy.utilities.iterables import iterable
  58. from sympy.utilities.misc import debug
  59. def Rule(name, props=""):
  60. # GOTCHA: namedtuple class name not considered!
  61. def __eq__(self, other):
  62. return self.__class__ == other.__class__ and tuple.__eq__(self, other)
  63. __neq__ = lambda self, other: not __eq__(self, other)
  64. cls = namedtuple(name, props + " context symbol")
  65. cls.__eq__ = __eq__
  66. cls.__ne__ = __neq__
  67. return cls
  68. ConstantRule = Rule("ConstantRule", "constant")
  69. ConstantTimesRule = Rule("ConstantTimesRule", "constant other substep")
  70. PowerRule = Rule("PowerRule", "base exp")
  71. AddRule = Rule("AddRule", "substeps")
  72. URule = Rule("URule", "u_var u_func constant substep")
  73. PartsRule = Rule("PartsRule", "u dv v_step second_step")
  74. CyclicPartsRule = Rule("CyclicPartsRule", "parts_rules coefficient")
  75. TrigRule = Rule("TrigRule", "func arg")
  76. ExpRule = Rule("ExpRule", "base exp")
  77. ReciprocalRule = Rule("ReciprocalRule", "func")
  78. ArcsinRule = Rule("ArcsinRule")
  79. InverseHyperbolicRule = Rule("InverseHyperbolicRule", "func")
  80. AlternativeRule = Rule("AlternativeRule", "alternatives")
  81. DontKnowRule = Rule("DontKnowRule")
  82. DerivativeRule = Rule("DerivativeRule")
  83. RewriteRule = Rule("RewriteRule", "rewritten substep")
  84. PiecewiseRule = Rule("PiecewiseRule", "subfunctions")
  85. HeavisideRule = Rule("HeavisideRule", "harg ibnd substep")
  86. TrigSubstitutionRule = Rule("TrigSubstitutionRule",
  87. "theta func rewritten substep restriction")
  88. ArctanRule = Rule("ArctanRule", "a b c")
  89. ArccothRule = Rule("ArccothRule", "a b c")
  90. ArctanhRule = Rule("ArctanhRule", "a b c")
  91. JacobiRule = Rule("JacobiRule", "n a b")
  92. GegenbauerRule = Rule("GegenbauerRule", "n a")
  93. ChebyshevTRule = Rule("ChebyshevTRule", "n")
  94. ChebyshevURule = Rule("ChebyshevURule", "n")
  95. LegendreRule = Rule("LegendreRule", "n")
  96. HermiteRule = Rule("HermiteRule", "n")
  97. LaguerreRule = Rule("LaguerreRule", "n")
  98. AssocLaguerreRule = Rule("AssocLaguerreRule", "n a")
  99. CiRule = Rule("CiRule", "a b")
  100. ChiRule = Rule("ChiRule", "a b")
  101. EiRule = Rule("EiRule", "a b")
  102. SiRule = Rule("SiRule", "a b")
  103. ShiRule = Rule("ShiRule", "a b")
  104. ErfRule = Rule("ErfRule", "a b c")
  105. FresnelCRule = Rule("FresnelCRule", "a b c")
  106. FresnelSRule = Rule("FresnelSRule", "a b c")
  107. LiRule = Rule("LiRule", "a b")
  108. PolylogRule = Rule("PolylogRule", "a b")
  109. UpperGammaRule = Rule("UpperGammaRule", "a e")
  110. EllipticFRule = Rule("EllipticFRule", "a d")
  111. EllipticERule = Rule("EllipticERule", "a d")
  112. IntegralInfo = namedtuple('IntegralInfo', 'integrand symbol')
  113. evaluators = {}
  114. def evaluates(rule):
  115. def _evaluates(func):
  116. func.rule = rule
  117. evaluators[rule] = func
  118. return func
  119. return _evaluates
  120. def contains_dont_know(rule):
  121. if isinstance(rule, DontKnowRule):
  122. return True
  123. else:
  124. for val in rule:
  125. if isinstance(val, tuple):
  126. if contains_dont_know(val):
  127. return True
  128. elif isinstance(val, list):
  129. if any(contains_dont_know(i) for i in val):
  130. return True
  131. return False
  132. def manual_diff(f, symbol):
  133. """Derivative of f in form expected by find_substitutions
  134. SymPy's derivatives for some trig functions (like cot) aren't in a form
  135. that works well with finding substitutions; this replaces the
  136. derivatives for those particular forms with something that works better.
  137. """
  138. if f.args:
  139. arg = f.args[0]
  140. if isinstance(f, tan):
  141. return arg.diff(symbol) * sec(arg)**2
  142. elif isinstance(f, cot):
  143. return -arg.diff(symbol) * csc(arg)**2
  144. elif isinstance(f, sec):
  145. return arg.diff(symbol) * sec(arg) * tan(arg)
  146. elif isinstance(f, csc):
  147. return -arg.diff(symbol) * csc(arg) * cot(arg)
  148. elif isinstance(f, Add):
  149. return sum([manual_diff(arg, symbol) for arg in f.args])
  150. elif isinstance(f, Mul):
  151. if len(f.args) == 2 and isinstance(f.args[0], Number):
  152. return f.args[0] * manual_diff(f.args[1], symbol)
  153. return f.diff(symbol)
  154. def manual_subs(expr, *args):
  155. """
  156. A wrapper for `expr.subs(*args)` with additional logic for substitution
  157. of invertible functions.
  158. """
  159. if len(args) == 1:
  160. sequence = args[0]
  161. if isinstance(sequence, (Dict, Mapping)):
  162. sequence = sequence.items()
  163. elif not iterable(sequence):
  164. raise ValueError("Expected an iterable of (old, new) pairs")
  165. elif len(args) == 2:
  166. sequence = [args]
  167. else:
  168. raise ValueError("subs accepts either 1 or 2 arguments")
  169. new_subs = []
  170. for old, new in sequence:
  171. if isinstance(old, log):
  172. # If log(x) = y, then exp(a*log(x)) = exp(a*y)
  173. # that is, x**a = exp(a*y). Replace nontrivial powers of x
  174. # before subs turns them into `exp(y)**a`, but
  175. # do not replace x itself yet, to avoid `log(exp(y))`.
  176. x0 = old.args[0]
  177. expr = expr.replace(lambda x: x.is_Pow and x.base == x0,
  178. lambda x: exp(x.exp*new))
  179. new_subs.append((x0, exp(new)))
  180. return expr.subs(list(sequence) + new_subs)
  181. # Method based on that on SIN, described in "Symbolic Integration: The
  182. # Stormy Decade"
  183. inverse_trig_functions = (atan, asin, acos, acot, acsc, asec)
  184. def find_substitutions(integrand, symbol, u_var):
  185. results = []
  186. def test_subterm(u, u_diff):
  187. if u_diff == 0:
  188. return False
  189. substituted = integrand / u_diff
  190. if symbol not in substituted.free_symbols:
  191. # replaced everything already
  192. return False
  193. debug("substituted: {}, u: {}, u_var: {}".format(substituted, u, u_var))
  194. substituted = manual_subs(substituted, u, u_var).cancel()
  195. if symbol not in substituted.free_symbols:
  196. # avoid increasing the degree of a rational function
  197. if integrand.is_rational_function(symbol) and substituted.is_rational_function(u_var):
  198. deg_before = max([degree(t, symbol) for t in integrand.as_numer_denom()])
  199. deg_after = max([degree(t, u_var) for t in substituted.as_numer_denom()])
  200. if deg_after > deg_before:
  201. return False
  202. return substituted.as_independent(u_var, as_Add=False)
  203. # special treatment for substitutions u = (a*x+b)**(1/n)
  204. if (isinstance(u, Pow) and (1/u.exp).is_Integer and
  205. Abs(u.exp) < 1):
  206. a = Wild('a', exclude=[symbol])
  207. b = Wild('b', exclude=[symbol])
  208. match = u.base.match(a*symbol + b)
  209. if match:
  210. a, b = [match.get(i, S.Zero) for i in (a, b)]
  211. if a != 0 and b != 0:
  212. substituted = substituted.subs(symbol,
  213. (u_var**(1/u.exp) - b)/a)
  214. return substituted.as_independent(u_var, as_Add=False)
  215. return False
  216. def possible_subterms(term):
  217. if isinstance(term, (TrigonometricFunction,
  218. *inverse_trig_functions,
  219. exp, log, Heaviside)):
  220. return [term.args[0]]
  221. elif isinstance(term, (chebyshevt, chebyshevu,
  222. legendre, hermite, laguerre)):
  223. return [term.args[1]]
  224. elif isinstance(term, (gegenbauer, assoc_laguerre)):
  225. return [term.args[2]]
  226. elif isinstance(term, jacobi):
  227. return [term.args[3]]
  228. elif isinstance(term, Mul):
  229. r = []
  230. for u in term.args:
  231. r.append(u)
  232. r.extend(possible_subterms(u))
  233. return r
  234. elif isinstance(term, Pow):
  235. r = []
  236. if term.args[1].is_constant(symbol):
  237. r.append(term.args[0])
  238. elif term.args[0].is_constant(symbol):
  239. r.append(term.args[1])
  240. if term.args[1].is_Integer:
  241. r.extend([term.args[0]**d for d in divisors(term.args[1])
  242. if 1 < d < abs(term.args[1])])
  243. if term.args[0].is_Add:
  244. r.extend([t for t in possible_subterms(term.args[0])
  245. if t.is_Pow])
  246. return r
  247. elif isinstance(term, Add):
  248. r = []
  249. for arg in term.args:
  250. r.append(arg)
  251. r.extend(possible_subterms(arg))
  252. return r
  253. return []
  254. for u in possible_subterms(integrand):
  255. if u == symbol:
  256. continue
  257. u_diff = manual_diff(u, symbol)
  258. new_integrand = test_subterm(u, u_diff)
  259. if new_integrand is not False:
  260. constant, new_integrand = new_integrand
  261. if new_integrand == integrand.subs(symbol, u_var):
  262. continue
  263. substitution = (u, constant, new_integrand)
  264. if substitution not in results:
  265. results.append(substitution)
  266. return results
  267. def rewriter(condition, rewrite):
  268. """Strategy that rewrites an integrand."""
  269. def _rewriter(integral):
  270. integrand, symbol = integral
  271. debug("Integral: {} is rewritten with {} on symbol: {}".format(integrand, rewrite, symbol))
  272. if condition(*integral):
  273. rewritten = rewrite(*integral)
  274. if rewritten != integrand:
  275. substep = integral_steps(rewritten, symbol)
  276. if not isinstance(substep, DontKnowRule) and substep:
  277. return RewriteRule(
  278. rewritten,
  279. substep,
  280. integrand, symbol)
  281. return _rewriter
  282. def proxy_rewriter(condition, rewrite):
  283. """Strategy that rewrites an integrand based on some other criteria."""
  284. def _proxy_rewriter(criteria):
  285. criteria, integral = criteria
  286. integrand, symbol = integral
  287. debug("Integral: {} is rewritten with {} on symbol: {} and criteria: {}".format(integrand, rewrite, symbol, criteria))
  288. args = criteria + list(integral)
  289. if condition(*args):
  290. rewritten = rewrite(*args)
  291. if rewritten != integrand:
  292. return RewriteRule(
  293. rewritten,
  294. integral_steps(rewritten, symbol),
  295. integrand, symbol)
  296. return _proxy_rewriter
  297. def multiplexer(conditions):
  298. """Apply the rule that matches the condition, else None"""
  299. def multiplexer_rl(expr):
  300. for key, rule in conditions.items():
  301. if key(expr):
  302. return rule(expr)
  303. return multiplexer_rl
  304. def alternatives(*rules):
  305. """Strategy that makes an AlternativeRule out of multiple possible results."""
  306. def _alternatives(integral):
  307. alts = []
  308. count = 0
  309. debug("List of Alternative Rules")
  310. for rule in rules:
  311. count = count + 1
  312. debug("Rule {}: {}".format(count, rule))
  313. result = rule(integral)
  314. if (result and not isinstance(result, DontKnowRule) and
  315. result != integral and result not in alts):
  316. alts.append(result)
  317. if len(alts) == 1:
  318. return alts[0]
  319. elif alts:
  320. doable = [rule for rule in alts if not contains_dont_know(rule)]
  321. if doable:
  322. return AlternativeRule(doable, *integral)
  323. else:
  324. return AlternativeRule(alts, *integral)
  325. return _alternatives
  326. def constant_rule(integral):
  327. return ConstantRule(integral.integrand, *integral)
  328. def power_rule(integral):
  329. integrand, symbol = integral
  330. base, expt = integrand.as_base_exp()
  331. if symbol not in expt.free_symbols and isinstance(base, Symbol):
  332. if simplify(expt + 1) == 0:
  333. return ReciprocalRule(base, integrand, symbol)
  334. return PowerRule(base, expt, integrand, symbol)
  335. elif symbol not in base.free_symbols and isinstance(expt, Symbol):
  336. rule = ExpRule(base, expt, integrand, symbol)
  337. if fuzzy_not(log(base).is_zero):
  338. return rule
  339. elif log(base).is_zero:
  340. return ConstantRule(1, 1, symbol)
  341. return PiecewiseRule([
  342. (rule, Ne(log(base), 0)),
  343. (ConstantRule(1, 1, symbol), True)
  344. ], integrand, symbol)
  345. def exp_rule(integral):
  346. integrand, symbol = integral
  347. if isinstance(integrand.args[0], Symbol):
  348. return ExpRule(E, integrand.args[0], integrand, symbol)
  349. def orthogonal_poly_rule(integral):
  350. orthogonal_poly_classes = {
  351. jacobi: JacobiRule,
  352. gegenbauer: GegenbauerRule,
  353. chebyshevt: ChebyshevTRule,
  354. chebyshevu: ChebyshevURule,
  355. legendre: LegendreRule,
  356. hermite: HermiteRule,
  357. laguerre: LaguerreRule,
  358. assoc_laguerre: AssocLaguerreRule
  359. }
  360. orthogonal_poly_var_index = {
  361. jacobi: 3,
  362. gegenbauer: 2,
  363. assoc_laguerre: 2
  364. }
  365. integrand, symbol = integral
  366. for klass in orthogonal_poly_classes:
  367. if isinstance(integrand, klass):
  368. var_index = orthogonal_poly_var_index.get(klass, 1)
  369. if (integrand.args[var_index] is symbol and not
  370. any(v.has(symbol) for v in integrand.args[:var_index])):
  371. args = integrand.args[:var_index] + (integrand, symbol)
  372. return orthogonal_poly_classes[klass](*args)
  373. def special_function_rule(integral):
  374. integrand, symbol = integral
  375. a = Wild('a', exclude=[symbol], properties=[lambda x: not x.is_zero])
  376. b = Wild('b', exclude=[symbol])
  377. c = Wild('c', exclude=[symbol])
  378. d = Wild('d', exclude=[symbol], properties=[lambda x: not x.is_zero])
  379. e = Wild('e', exclude=[symbol], properties=[
  380. lambda x: not (x.is_nonnegative and x.is_integer)])
  381. wilds = (a, b, c, d, e)
  382. # patterns consist of a SymPy class, a wildcard expr, an optional
  383. # condition coded as a lambda (when Wild properties are not enough),
  384. # followed by an applicable rule
  385. patterns = (
  386. (Mul, exp(a*symbol + b)/symbol, None, EiRule),
  387. (Mul, cos(a*symbol + b)/symbol, None, CiRule),
  388. (Mul, cosh(a*symbol + b)/symbol, None, ChiRule),
  389. (Mul, sin(a*symbol + b)/symbol, None, SiRule),
  390. (Mul, sinh(a*symbol + b)/symbol, None, ShiRule),
  391. (Pow, 1/log(a*symbol + b), None, LiRule),
  392. (exp, exp(a*symbol**2 + b*symbol + c), None, ErfRule),
  393. (sin, sin(a*symbol**2 + b*symbol + c), None, FresnelSRule),
  394. (cos, cos(a*symbol**2 + b*symbol + c), None, FresnelCRule),
  395. (Mul, symbol**e*exp(a*symbol), None, UpperGammaRule),
  396. (Mul, polylog(b, a*symbol)/symbol, None, PolylogRule),
  397. (Pow, 1/sqrt(a - d*sin(symbol)**2),
  398. lambda a, d: a != d, EllipticFRule),
  399. (Pow, sqrt(a - d*sin(symbol)**2),
  400. lambda a, d: a != d, EllipticERule),
  401. )
  402. for p in patterns:
  403. if isinstance(integrand, p[0]):
  404. match = integrand.match(p[1])
  405. if match:
  406. wild_vals = tuple(match.get(w) for w in wilds
  407. if match.get(w) is not None)
  408. if p[2] is None or p[2](*wild_vals):
  409. args = wild_vals + (integrand, symbol)
  410. return p[3](*args)
  411. def inverse_trig_rule(integral):
  412. integrand, symbol = integral
  413. base, exp = integrand.as_base_exp()
  414. a = Wild('a', exclude=[symbol])
  415. b = Wild('b', exclude=[symbol])
  416. match = base.match(a + b*symbol**2)
  417. if not match:
  418. return
  419. def negative(x):
  420. return x.is_negative or x.could_extract_minus_sign()
  421. def ArcsinhRule(integrand, symbol):
  422. return InverseHyperbolicRule(asinh, integrand, symbol)
  423. def ArccoshRule(integrand, symbol):
  424. return InverseHyperbolicRule(acosh, integrand, symbol)
  425. def make_inverse_trig(RuleClass, base_exp, a, sign_a, b, sign_b):
  426. u_var = Dummy("u")
  427. current_base = base
  428. current_symbol = symbol
  429. constant = u_func = u_constant = substep = None
  430. factored = integrand
  431. if a != 1:
  432. constant = a**base_exp
  433. current_base = sign_a + sign_b * (b/a) * current_symbol**2
  434. factored = current_base ** base_exp
  435. if (b/a) != 1:
  436. u_func = sqrt(b/a) * symbol
  437. u_constant = sqrt(a/b)
  438. current_symbol = u_var
  439. current_base = sign_a + sign_b * current_symbol**2
  440. substep = RuleClass(current_base ** base_exp, current_symbol)
  441. if u_func is not None:
  442. if u_constant != 1 and substep is not None:
  443. substep = ConstantTimesRule(
  444. u_constant, current_base ** base_exp, substep,
  445. u_constant * current_base ** base_exp, symbol)
  446. substep = URule(u_var, u_func, u_constant, substep, factored, symbol)
  447. if constant is not None and substep is not None:
  448. substep = ConstantTimesRule(constant, factored, substep, integrand, symbol)
  449. return substep
  450. a, b = [match.get(i, S.Zero) for i in (a, b)]
  451. # list of (rule, base_exp, a, sign_a, b, sign_b, condition)
  452. possibilities = []
  453. if simplify(2*exp + 1) == 0:
  454. possibilities.append((ArcsinRule, exp, a, 1, -b, -1, And(a > 0, b < 0)))
  455. possibilities.append((ArcsinhRule, exp, a, 1, b, 1, And(a > 0, b > 0)))
  456. possibilities.append((ArccoshRule, exp, -a, -1, b, 1, And(a < 0, b > 0)))
  457. possibilities = [p for p in possibilities if p[-1] is not S.false]
  458. if a.is_number and b.is_number:
  459. possibility = [p for p in possibilities if p[-1] is S.true]
  460. if len(possibility) == 1:
  461. return make_inverse_trig(*possibility[0][:-1])
  462. elif possibilities:
  463. return PiecewiseRule(
  464. [(make_inverse_trig(*p[:-1]), p[-1]) for p in possibilities],
  465. integrand, symbol)
  466. def add_rule(integral):
  467. integrand, symbol = integral
  468. results = [integral_steps(g, symbol)
  469. for g in integrand.as_ordered_terms()]
  470. return None if None in results else AddRule(results, integrand, symbol)
  471. def mul_rule(integral):
  472. integrand, symbol = integral
  473. # Constant times function case
  474. coeff, f = integrand.as_independent(symbol)
  475. next_step = integral_steps(f, symbol)
  476. if coeff != 1 and next_step is not None:
  477. return ConstantTimesRule(
  478. coeff, f,
  479. next_step,
  480. integrand, symbol)
  481. def _parts_rule(integrand, symbol):
  482. # LIATE rule:
  483. # log, inverse trig, algebraic, trigonometric, exponential
  484. def pull_out_algebraic(integrand):
  485. integrand = integrand.cancel().together()
  486. # iterating over Piecewise args would not work here
  487. algebraic = ([] if isinstance(integrand, Piecewise)
  488. else [arg for arg in integrand.args if arg.is_algebraic_expr(symbol)])
  489. if algebraic:
  490. u = Mul(*algebraic)
  491. dv = (integrand / u).cancel()
  492. return u, dv
  493. def pull_out_u(*functions):
  494. def pull_out_u_rl(integrand):
  495. if any(integrand.has(f) for f in functions):
  496. args = [arg for arg in integrand.args
  497. if any(isinstance(arg, cls) for cls in functions)]
  498. if args:
  499. u = reduce(lambda a,b: a*b, args)
  500. dv = integrand / u
  501. return u, dv
  502. return pull_out_u_rl
  503. liate_rules = [pull_out_u(log), pull_out_u(*inverse_trig_functions),
  504. pull_out_algebraic, pull_out_u(sin, cos),
  505. pull_out_u(exp)]
  506. dummy = Dummy("temporary")
  507. # we can integrate log(x) and atan(x) by setting dv = 1
  508. if isinstance(integrand, (log, *inverse_trig_functions)):
  509. integrand = dummy * integrand
  510. for index, rule in enumerate(liate_rules):
  511. result = rule(integrand)
  512. if result:
  513. u, dv = result
  514. # Don't pick u to be a constant if possible
  515. if symbol not in u.free_symbols and not u.has(dummy):
  516. return
  517. u = u.subs(dummy, 1)
  518. dv = dv.subs(dummy, 1)
  519. # Don't pick a non-polynomial algebraic to be differentiated
  520. if rule == pull_out_algebraic and not u.is_polynomial(symbol):
  521. return
  522. # Don't trade one logarithm for another
  523. if isinstance(u, log):
  524. rec_dv = 1/dv
  525. if (rec_dv.is_polynomial(symbol) and
  526. degree(rec_dv, symbol) == 1):
  527. return
  528. # Can integrate a polynomial times OrthogonalPolynomial
  529. if rule == pull_out_algebraic and isinstance(dv, OrthogonalPolynomial):
  530. v_step = integral_steps(dv, symbol)
  531. if contains_dont_know(v_step):
  532. return
  533. else:
  534. du = u.diff(symbol)
  535. v = _manualintegrate(v_step)
  536. return u, dv, v, du, v_step
  537. # make sure dv is amenable to integration
  538. accept = False
  539. if index < 2: # log and inverse trig are usually worth trying
  540. accept = True
  541. elif (rule == pull_out_algebraic and dv.args and
  542. all(isinstance(a, (sin, cos, exp))
  543. for a in dv.args)):
  544. accept = True
  545. else:
  546. for lrule in liate_rules[index + 1:]:
  547. r = lrule(integrand)
  548. if r and r[0].subs(dummy, 1).equals(dv):
  549. accept = True
  550. break
  551. if accept:
  552. du = u.diff(symbol)
  553. v_step = integral_steps(simplify(dv), symbol)
  554. if not contains_dont_know(v_step):
  555. v = _manualintegrate(v_step)
  556. return u, dv, v, du, v_step
  557. def parts_rule(integral):
  558. integrand, symbol = integral
  559. constant, integrand = integrand.as_coeff_Mul()
  560. result = _parts_rule(integrand, symbol)
  561. steps = []
  562. if result:
  563. u, dv, v, du, v_step = result
  564. debug("u : {}, dv : {}, v : {}, du : {}, v_step: {}".format(u, dv, v, du, v_step))
  565. steps.append(result)
  566. if isinstance(v, Integral):
  567. return
  568. # Set a limit on the number of times u can be used
  569. if isinstance(u, (sin, cos, exp, sinh, cosh)):
  570. cachekey = u.xreplace({symbol: _cache_dummy})
  571. if _parts_u_cache[cachekey] > 2:
  572. return
  573. _parts_u_cache[cachekey] += 1
  574. # Try cyclic integration by parts a few times
  575. for _ in range(4):
  576. debug("Cyclic integration {} with v: {}, du: {}, integrand: {}".format(_, v, du, integrand))
  577. coefficient = ((v * du) / integrand).cancel()
  578. if coefficient == 1:
  579. break
  580. if symbol not in coefficient.free_symbols:
  581. rule = CyclicPartsRule(
  582. [PartsRule(u, dv, v_step, None, None, None)
  583. for (u, dv, v, du, v_step) in steps],
  584. (-1) ** len(steps) * coefficient,
  585. integrand, symbol
  586. )
  587. if (constant != 1) and rule:
  588. rule = ConstantTimesRule(constant, integrand, rule,
  589. constant * integrand, symbol)
  590. return rule
  591. # _parts_rule is sensitive to constants, factor it out
  592. next_constant, next_integrand = (v * du).as_coeff_Mul()
  593. result = _parts_rule(next_integrand, symbol)
  594. if result:
  595. u, dv, v, du, v_step = result
  596. u *= next_constant
  597. du *= next_constant
  598. steps.append((u, dv, v, du, v_step))
  599. else:
  600. break
  601. def make_second_step(steps, integrand):
  602. if steps:
  603. u, dv, v, du, v_step = steps[0]
  604. return PartsRule(u, dv, v_step,
  605. make_second_step(steps[1:], v * du),
  606. integrand, symbol)
  607. else:
  608. steps = integral_steps(integrand, symbol)
  609. if steps:
  610. return steps
  611. else:
  612. return DontKnowRule(integrand, symbol)
  613. if steps:
  614. u, dv, v, du, v_step = steps[0]
  615. rule = PartsRule(u, dv, v_step,
  616. make_second_step(steps[1:], v * du),
  617. integrand, symbol)
  618. if (constant != 1) and rule:
  619. rule = ConstantTimesRule(constant, integrand, rule,
  620. constant * integrand, symbol)
  621. return rule
  622. def trig_rule(integral):
  623. integrand, symbol = integral
  624. if isinstance(integrand, (sin, cos)):
  625. arg = integrand.args[0]
  626. if not isinstance(arg, Symbol):
  627. return # perhaps a substitution can deal with it
  628. if isinstance(integrand, sin):
  629. func = 'sin'
  630. else:
  631. func = 'cos'
  632. return TrigRule(func, arg, integrand, symbol)
  633. if integrand == sec(symbol)**2:
  634. return TrigRule('sec**2', symbol, integrand, symbol)
  635. elif integrand == csc(symbol)**2:
  636. return TrigRule('csc**2', symbol, integrand, symbol)
  637. if isinstance(integrand, tan):
  638. rewritten = sin(*integrand.args) / cos(*integrand.args)
  639. elif isinstance(integrand, cot):
  640. rewritten = cos(*integrand.args) / sin(*integrand.args)
  641. elif isinstance(integrand, sec):
  642. arg = integrand.args[0]
  643. rewritten = ((sec(arg)**2 + tan(arg) * sec(arg)) /
  644. (sec(arg) + tan(arg)))
  645. elif isinstance(integrand, csc):
  646. arg = integrand.args[0]
  647. rewritten = ((csc(arg)**2 + cot(arg) * csc(arg)) /
  648. (csc(arg) + cot(arg)))
  649. else:
  650. return
  651. return RewriteRule(
  652. rewritten,
  653. integral_steps(rewritten, symbol),
  654. integrand, symbol
  655. )
  656. def trig_product_rule(integral):
  657. integrand, symbol = integral
  658. sectan = sec(symbol) * tan(symbol)
  659. q = integrand / sectan
  660. if symbol not in q.free_symbols:
  661. rule = TrigRule('sec*tan', symbol, sectan, symbol)
  662. if q != 1 and rule:
  663. rule = ConstantTimesRule(q, sectan, rule, integrand, symbol)
  664. return rule
  665. csccot = -csc(symbol) * cot(symbol)
  666. q = integrand / csccot
  667. if symbol not in q.free_symbols:
  668. rule = TrigRule('csc*cot', symbol, csccot, symbol)
  669. if q != 1 and rule:
  670. rule = ConstantTimesRule(q, csccot, rule, integrand, symbol)
  671. return rule
  672. def quadratic_denom_rule(integral):
  673. integrand, symbol = integral
  674. a = Wild('a', exclude=[symbol])
  675. b = Wild('b', exclude=[symbol])
  676. c = Wild('c', exclude=[symbol])
  677. match = integrand.match(a / (b * symbol ** 2 + c))
  678. if match:
  679. a, b, c = match[a], match[b], match[c]
  680. if b.is_extended_real and c.is_extended_real:
  681. return PiecewiseRule([(ArctanRule(a, b, c, integrand, symbol), Gt(c / b, 0)),
  682. (ArccothRule(a, b, c, integrand, symbol), And(Gt(symbol ** 2, -c / b), Lt(c / b, 0))),
  683. (ArctanhRule(a, b, c, integrand, symbol), And(Lt(symbol ** 2, -c / b), Lt(c / b, 0))),
  684. ], integrand, symbol)
  685. else:
  686. return ArctanRule(a, b, c, integrand, symbol)
  687. d = Wild('d', exclude=[symbol])
  688. match2 = integrand.match(a / (b * symbol ** 2 + c * symbol + d))
  689. if match2:
  690. b, c = match2[b], match2[c]
  691. if b.is_zero:
  692. return
  693. u = Dummy('u')
  694. u_func = symbol + c/(2*b)
  695. integrand2 = integrand.subs(symbol, u - c / (2*b))
  696. next_step = integral_steps(integrand2, u)
  697. if next_step:
  698. return URule(u, u_func, None, next_step, integrand2, symbol)
  699. else:
  700. return
  701. e = Wild('e', exclude=[symbol])
  702. match3 = integrand.match((a* symbol + b) / (c * symbol ** 2 + d * symbol + e))
  703. if match3:
  704. a, b, c, d, e = match3[a], match3[b], match3[c], match3[d], match3[e]
  705. if c.is_zero:
  706. return
  707. denominator = c * symbol**2 + d * symbol + e
  708. const = a/(2*c)
  709. numer1 = (2*c*symbol+d)
  710. numer2 = - const*d + b
  711. u = Dummy('u')
  712. step1 = URule(u,
  713. denominator,
  714. const,
  715. integral_steps(u**(-1), u),
  716. integrand,
  717. symbol)
  718. if const != 1:
  719. step1 = ConstantTimesRule(const,
  720. numer1/denominator,
  721. step1,
  722. const*numer1/denominator,
  723. symbol)
  724. if numer2.is_zero:
  725. return step1
  726. step2 = integral_steps(numer2/denominator, symbol)
  727. substeps = AddRule([step1, step2], integrand, symbol)
  728. rewriten = const*numer1/denominator+numer2/denominator
  729. return RewriteRule(rewriten, substeps, integrand, symbol)
  730. return
  731. def root_mul_rule(integral):
  732. integrand, symbol = integral
  733. a = Wild('a', exclude=[symbol])
  734. b = Wild('b', exclude=[symbol])
  735. c = Wild('c')
  736. match = integrand.match(sqrt(a * symbol + b) * c)
  737. if not match:
  738. return
  739. a, b, c = match[a], match[b], match[c]
  740. d = Wild('d', exclude=[symbol])
  741. e = Wild('e', exclude=[symbol])
  742. f = Wild('f')
  743. recursion_test = c.match(sqrt(d * symbol + e) * f)
  744. if recursion_test:
  745. return
  746. u = Dummy('u')
  747. u_func = sqrt(a * symbol + b)
  748. integrand = integrand.subs(u_func, u)
  749. integrand = integrand.subs(symbol, (u**2 - b) / a)
  750. integrand = integrand * 2 * u / a
  751. next_step = integral_steps(integrand, u)
  752. if next_step:
  753. return URule(u, u_func, None, next_step, integrand, symbol)
  754. @cacheit
  755. def make_wilds(symbol):
  756. a = Wild('a', exclude=[symbol])
  757. b = Wild('b', exclude=[symbol])
  758. m = Wild('m', exclude=[symbol], properties=[lambda n: isinstance(n, Integer)])
  759. n = Wild('n', exclude=[symbol], properties=[lambda n: isinstance(n, Integer)])
  760. return a, b, m, n
  761. @cacheit
  762. def sincos_pattern(symbol):
  763. a, b, m, n = make_wilds(symbol)
  764. pattern = sin(a*symbol)**m * cos(b*symbol)**n
  765. return pattern, a, b, m, n
  766. @cacheit
  767. def tansec_pattern(symbol):
  768. a, b, m, n = make_wilds(symbol)
  769. pattern = tan(a*symbol)**m * sec(b*symbol)**n
  770. return pattern, a, b, m, n
  771. @cacheit
  772. def cotcsc_pattern(symbol):
  773. a, b, m, n = make_wilds(symbol)
  774. pattern = cot(a*symbol)**m * csc(b*symbol)**n
  775. return pattern, a, b, m, n
  776. @cacheit
  777. def heaviside_pattern(symbol):
  778. m = Wild('m', exclude=[symbol])
  779. b = Wild('b', exclude=[symbol])
  780. g = Wild('g')
  781. pattern = Heaviside(m*symbol + b) * g
  782. return pattern, m, b, g
  783. def uncurry(func):
  784. def uncurry_rl(args):
  785. return func(*args)
  786. return uncurry_rl
  787. def trig_rewriter(rewrite):
  788. def trig_rewriter_rl(args):
  789. a, b, m, n, integrand, symbol = args
  790. rewritten = rewrite(a, b, m, n, integrand, symbol)
  791. if rewritten != integrand:
  792. return RewriteRule(
  793. rewritten,
  794. integral_steps(rewritten, symbol),
  795. integrand, symbol)
  796. return trig_rewriter_rl
  797. sincos_botheven_condition = uncurry(
  798. lambda a, b, m, n, i, s: m.is_even and n.is_even and
  799. m.is_nonnegative and n.is_nonnegative)
  800. sincos_botheven = trig_rewriter(
  801. lambda a, b, m, n, i, symbol: ( (((1 - cos(2*a*symbol)) / 2) ** (m / 2)) *
  802. (((1 + cos(2*b*symbol)) / 2) ** (n / 2)) ))
  803. sincos_sinodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd and m >= 3)
  804. sincos_sinodd = trig_rewriter(
  805. lambda a, b, m, n, i, symbol: ( (1 - cos(a*symbol)**2)**((m - 1) / 2) *
  806. sin(a*symbol) *
  807. cos(b*symbol) ** n))
  808. sincos_cosodd_condition = uncurry(lambda a, b, m, n, i, s: n.is_odd and n >= 3)
  809. sincos_cosodd = trig_rewriter(
  810. lambda a, b, m, n, i, symbol: ( (1 - sin(b*symbol)**2)**((n - 1) / 2) *
  811. cos(b*symbol) *
  812. sin(a*symbol) ** m))
  813. tansec_seceven_condition = uncurry(lambda a, b, m, n, i, s: n.is_even and n >= 4)
  814. tansec_seceven = trig_rewriter(
  815. lambda a, b, m, n, i, symbol: ( (1 + tan(b*symbol)**2) ** (n/2 - 1) *
  816. sec(b*symbol)**2 *
  817. tan(a*symbol) ** m ))
  818. tansec_tanodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd)
  819. tansec_tanodd = trig_rewriter(
  820. lambda a, b, m, n, i, symbol: ( (sec(a*symbol)**2 - 1) ** ((m - 1) / 2) *
  821. tan(a*symbol) *
  822. sec(b*symbol) ** n ))
  823. tan_tansquared_condition = uncurry(lambda a, b, m, n, i, s: m == 2 and n == 0)
  824. tan_tansquared = trig_rewriter(
  825. lambda a, b, m, n, i, symbol: ( sec(a*symbol)**2 - 1))
  826. cotcsc_csceven_condition = uncurry(lambda a, b, m, n, i, s: n.is_even and n >= 4)
  827. cotcsc_csceven = trig_rewriter(
  828. lambda a, b, m, n, i, symbol: ( (1 + cot(b*symbol)**2) ** (n/2 - 1) *
  829. csc(b*symbol)**2 *
  830. cot(a*symbol) ** m ))
  831. cotcsc_cotodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd)
  832. cotcsc_cotodd = trig_rewriter(
  833. lambda a, b, m, n, i, symbol: ( (csc(a*symbol)**2 - 1) ** ((m - 1) / 2) *
  834. cot(a*symbol) *
  835. csc(b*symbol) ** n ))
  836. def trig_sincos_rule(integral):
  837. integrand, symbol = integral
  838. if any(integrand.has(f) for f in (sin, cos)):
  839. pattern, a, b, m, n = sincos_pattern(symbol)
  840. match = integrand.match(pattern)
  841. if not match:
  842. return
  843. return multiplexer({
  844. sincos_botheven_condition: sincos_botheven,
  845. sincos_sinodd_condition: sincos_sinodd,
  846. sincos_cosodd_condition: sincos_cosodd
  847. })(tuple(
  848. [match.get(i, S.Zero) for i in (a, b, m, n)] +
  849. [integrand, symbol]))
  850. def trig_tansec_rule(integral):
  851. integrand, symbol = integral
  852. integrand = integrand.subs({
  853. 1 / cos(symbol): sec(symbol)
  854. })
  855. if any(integrand.has(f) for f in (tan, sec)):
  856. pattern, a, b, m, n = tansec_pattern(symbol)
  857. match = integrand.match(pattern)
  858. if not match:
  859. return
  860. return multiplexer({
  861. tansec_tanodd_condition: tansec_tanodd,
  862. tansec_seceven_condition: tansec_seceven,
  863. tan_tansquared_condition: tan_tansquared
  864. })(tuple(
  865. [match.get(i, S.Zero) for i in (a, b, m, n)] +
  866. [integrand, symbol]))
  867. def trig_cotcsc_rule(integral):
  868. integrand, symbol = integral
  869. integrand = integrand.subs({
  870. 1 / sin(symbol): csc(symbol),
  871. 1 / tan(symbol): cot(symbol),
  872. cos(symbol) / tan(symbol): cot(symbol)
  873. })
  874. if any(integrand.has(f) for f in (cot, csc)):
  875. pattern, a, b, m, n = cotcsc_pattern(symbol)
  876. match = integrand.match(pattern)
  877. if not match:
  878. return
  879. return multiplexer({
  880. cotcsc_cotodd_condition: cotcsc_cotodd,
  881. cotcsc_csceven_condition: cotcsc_csceven
  882. })(tuple(
  883. [match.get(i, S.Zero) for i in (a, b, m, n)] +
  884. [integrand, symbol]))
  885. def trig_sindouble_rule(integral):
  886. integrand, symbol = integral
  887. a = Wild('a', exclude=[sin(2*symbol)])
  888. match = integrand.match(sin(2*symbol)*a)
  889. if match:
  890. sin_double = 2*sin(symbol)*cos(symbol)/sin(2*symbol)
  891. return integral_steps(integrand * sin_double, symbol)
  892. def trig_powers_products_rule(integral):
  893. return do_one(null_safe(trig_sincos_rule),
  894. null_safe(trig_tansec_rule),
  895. null_safe(trig_cotcsc_rule),
  896. null_safe(trig_sindouble_rule))(integral)
  897. def trig_substitution_rule(integral):
  898. integrand, symbol = integral
  899. A = Wild('a', exclude=[0, symbol])
  900. B = Wild('b', exclude=[0, symbol])
  901. theta = Dummy("theta")
  902. target_pattern = A + B*symbol**2
  903. matches = integrand.find(target_pattern)
  904. for expr in matches:
  905. match = expr.match(target_pattern)
  906. a = match.get(A, S.Zero)
  907. b = match.get(B, S.Zero)
  908. a_positive = ((a.is_number and a > 0) or a.is_positive)
  909. b_positive = ((b.is_number and b > 0) or b.is_positive)
  910. a_negative = ((a.is_number and a < 0) or a.is_negative)
  911. b_negative = ((b.is_number and b < 0) or b.is_negative)
  912. x_func = None
  913. if a_positive and b_positive:
  914. # a**2 + b*x**2. Assume sec(theta) > 0, -pi/2 < theta < pi/2
  915. x_func = (sqrt(a)/sqrt(b)) * tan(theta)
  916. # Do not restrict the domain: tan(theta) takes on any real
  917. # value on the interval -pi/2 < theta < pi/2 so x takes on
  918. # any value
  919. restriction = True
  920. elif a_positive and b_negative:
  921. # a**2 - b*x**2. Assume cos(theta) > 0, -pi/2 < theta < pi/2
  922. constant = sqrt(a)/sqrt(-b)
  923. x_func = constant * sin(theta)
  924. restriction = And(symbol > -constant, symbol < constant)
  925. elif a_negative and b_positive:
  926. # b*x**2 - a**2. Assume sin(theta) > 0, 0 < theta < pi
  927. constant = sqrt(-a)/sqrt(b)
  928. x_func = constant * sec(theta)
  929. restriction = And(symbol > -constant, symbol < constant)
  930. if x_func:
  931. # Manually simplify sqrt(trig(theta)**2) to trig(theta)
  932. # Valid due to assumed domain restriction
  933. substitutions = {}
  934. for f in [sin, cos, tan,
  935. sec, csc, cot]:
  936. substitutions[sqrt(f(theta)**2)] = f(theta)
  937. substitutions[sqrt(f(theta)**(-2))] = 1/f(theta)
  938. replaced = integrand.subs(symbol, x_func).trigsimp()
  939. replaced = manual_subs(replaced, substitutions)
  940. if not replaced.has(symbol):
  941. replaced *= manual_diff(x_func, theta)
  942. replaced = replaced.trigsimp()
  943. secants = replaced.find(1/cos(theta))
  944. if secants:
  945. replaced = replaced.xreplace({
  946. 1/cos(theta): sec(theta)
  947. })
  948. substep = integral_steps(replaced, theta)
  949. if not contains_dont_know(substep):
  950. return TrigSubstitutionRule(
  951. theta, x_func, replaced, substep, restriction,
  952. integrand, symbol)
  953. def heaviside_rule(integral):
  954. integrand, symbol = integral
  955. pattern, m, b, g = heaviside_pattern(symbol)
  956. match = integrand.match(pattern)
  957. if match and 0 != match[g]:
  958. # f = Heaviside(m*x + b)*g
  959. v_step = integral_steps(match[g], symbol)
  960. result = _manualintegrate(v_step)
  961. m, b = match[m], match[b]
  962. return HeavisideRule(m*symbol + b, -b/m, result, integrand, symbol)
  963. def substitution_rule(integral):
  964. integrand, symbol = integral
  965. u_var = Dummy("u")
  966. substitutions = find_substitutions(integrand, symbol, u_var)
  967. count = 0
  968. if substitutions:
  969. debug("List of Substitution Rules")
  970. ways = []
  971. for u_func, c, substituted in substitutions:
  972. subrule = integral_steps(substituted, u_var)
  973. count = count + 1
  974. debug("Rule {}: {}".format(count, subrule))
  975. if contains_dont_know(subrule):
  976. continue
  977. if simplify(c - 1) != 0:
  978. _, denom = c.as_numer_denom()
  979. if subrule:
  980. subrule = ConstantTimesRule(c, substituted, subrule, substituted, u_var)
  981. if denom.free_symbols:
  982. piecewise = []
  983. could_be_zero = []
  984. if isinstance(denom, Mul):
  985. could_be_zero = denom.args
  986. else:
  987. could_be_zero.append(denom)
  988. for expr in could_be_zero:
  989. if not fuzzy_not(expr.is_zero):
  990. substep = integral_steps(manual_subs(integrand, expr, 0), symbol)
  991. if substep:
  992. piecewise.append((
  993. substep,
  994. Eq(expr, 0)
  995. ))
  996. piecewise.append((subrule, True))
  997. subrule = PiecewiseRule(piecewise, substituted, symbol)
  998. ways.append(URule(u_var, u_func, c,
  999. subrule,
  1000. integrand, symbol))
  1001. if len(ways) > 1:
  1002. return AlternativeRule(ways, integrand, symbol)
  1003. elif ways:
  1004. return ways[0]
  1005. elif integrand.has(exp):
  1006. u_func = exp(symbol)
  1007. c = 1
  1008. substituted = integrand / u_func.diff(symbol)
  1009. substituted = substituted.subs(u_func, u_var)
  1010. if symbol not in substituted.free_symbols:
  1011. return URule(u_var, u_func, c,
  1012. integral_steps(substituted, u_var),
  1013. integrand, symbol)
  1014. partial_fractions_rule = rewriter(
  1015. lambda integrand, symbol: integrand.is_rational_function(),
  1016. lambda integrand, symbol: integrand.apart(symbol))
  1017. cancel_rule = rewriter(
  1018. # lambda integrand, symbol: integrand.is_algebraic_expr(),
  1019. # lambda integrand, symbol: isinstance(integrand, Mul),
  1020. lambda integrand, symbol: True,
  1021. lambda integrand, symbol: integrand.cancel())
  1022. distribute_expand_rule = rewriter(
  1023. lambda integrand, symbol: (
  1024. all(arg.is_Pow or arg.is_polynomial(symbol) for arg in integrand.args)
  1025. or isinstance(integrand, Pow)
  1026. or isinstance(integrand, Mul)),
  1027. lambda integrand, symbol: integrand.expand())
  1028. trig_expand_rule = rewriter(
  1029. # If there are trig functions with different arguments, expand them
  1030. lambda integrand, symbol: (
  1031. len({a.args[0] for a in integrand.atoms(TrigonometricFunction)}) > 1),
  1032. lambda integrand, symbol: integrand.expand(trig=True))
  1033. def derivative_rule(integral):
  1034. integrand = integral[0]
  1035. diff_variables = integrand.variables
  1036. undifferentiated_function = integrand.expr
  1037. integrand_variables = undifferentiated_function.free_symbols
  1038. if integral.symbol in integrand_variables:
  1039. if integral.symbol in diff_variables:
  1040. return DerivativeRule(*integral)
  1041. else:
  1042. return DontKnowRule(integrand, integral.symbol)
  1043. else:
  1044. return ConstantRule(integral.integrand, *integral)
  1045. def rewrites_rule(integral):
  1046. integrand, symbol = integral
  1047. if integrand.match(1/cos(symbol)):
  1048. rewritten = integrand.subs(1/cos(symbol), sec(symbol))
  1049. return RewriteRule(rewritten, integral_steps(rewritten, symbol), integrand, symbol)
  1050. def fallback_rule(integral):
  1051. return DontKnowRule(*integral)
  1052. # Cache is used to break cyclic integrals.
  1053. # Need to use the same dummy variable in cached expressions for them to match.
  1054. # Also record "u" of integration by parts, to avoid infinite repetition.
  1055. _integral_cache = {} # type: tDict[Expr, Optional[Expr]]
  1056. _parts_u_cache = defaultdict(int) # type: tDict[Expr, int]
  1057. _cache_dummy = Dummy("z")
  1058. def integral_steps(integrand, symbol, **options):
  1059. """Returns the steps needed to compute an integral.
  1060. Explanation
  1061. ===========
  1062. This function attempts to mirror what a student would do by hand as
  1063. closely as possible.
  1064. SymPy Gamma uses this to provide a step-by-step explanation of an
  1065. integral. The code it uses to format the results of this function can be
  1066. found at
  1067. https://github.com/sympy/sympy_gamma/blob/master/app/logic/intsteps.py.
  1068. Examples
  1069. ========
  1070. >>> from sympy import exp, sin
  1071. >>> from sympy.integrals.manualintegrate import integral_steps
  1072. >>> from sympy.abc import x
  1073. >>> print(repr(integral_steps(exp(x) / (1 + exp(2 * x)), x))) \
  1074. # doctest: +NORMALIZE_WHITESPACE
  1075. URule(u_var=_u, u_func=exp(x), constant=1,
  1076. substep=PiecewiseRule(subfunctions=[(ArctanRule(a=1, b=1, c=1, context=1/(_u**2 + 1), symbol=_u), True),
  1077. (ArccothRule(a=1, b=1, c=1, context=1/(_u**2 + 1), symbol=_u), False),
  1078. (ArctanhRule(a=1, b=1, c=1, context=1/(_u**2 + 1), symbol=_u), False)],
  1079. context=1/(_u**2 + 1), symbol=_u), context=exp(x)/(exp(2*x) + 1), symbol=x)
  1080. >>> print(repr(integral_steps(sin(x), x))) \
  1081. # doctest: +NORMALIZE_WHITESPACE
  1082. TrigRule(func='sin', arg=x, context=sin(x), symbol=x)
  1083. >>> print(repr(integral_steps((x**2 + 3)**2, x))) \
  1084. # doctest: +NORMALIZE_WHITESPACE
  1085. RewriteRule(rewritten=x**4 + 6*x**2 + 9,
  1086. substep=AddRule(substeps=[PowerRule(base=x, exp=4, context=x**4, symbol=x),
  1087. ConstantTimesRule(constant=6, other=x**2,
  1088. substep=PowerRule(base=x, exp=2, context=x**2, symbol=x),
  1089. context=6*x**2, symbol=x),
  1090. ConstantRule(constant=9, context=9, symbol=x)],
  1091. context=x**4 + 6*x**2 + 9, symbol=x), context=(x**2 + 3)**2, symbol=x)
  1092. Returns
  1093. =======
  1094. rule : namedtuple
  1095. The first step; most rules have substeps that must also be
  1096. considered. These substeps can be evaluated using ``manualintegrate``
  1097. to obtain a result.
  1098. """
  1099. cachekey = integrand.xreplace({symbol: _cache_dummy})
  1100. if cachekey in _integral_cache:
  1101. if _integral_cache[cachekey] is None:
  1102. # Stop this attempt, because it leads around in a loop
  1103. return DontKnowRule(integrand, symbol)
  1104. else:
  1105. # TODO: This is for future development, as currently
  1106. # _integral_cache gets no values other than None
  1107. return (_integral_cache[cachekey].xreplace(_cache_dummy, symbol),
  1108. symbol)
  1109. else:
  1110. _integral_cache[cachekey] = None
  1111. integral = IntegralInfo(integrand, symbol)
  1112. def key(integral):
  1113. integrand = integral.integrand
  1114. if symbol not in integrand.free_symbols:
  1115. return Number
  1116. elif isinstance(integrand, TrigonometricFunction):
  1117. return TrigonometricFunction
  1118. elif isinstance(integrand, Derivative):
  1119. return Derivative
  1120. else:
  1121. for cls in (Pow, Symbol, exp, log,
  1122. Add, Mul, *inverse_trig_functions,
  1123. Heaviside, OrthogonalPolynomial):
  1124. if isinstance(integrand, cls):
  1125. return cls
  1126. def integral_is_subclass(*klasses):
  1127. def _integral_is_subclass(integral):
  1128. k = key(integral)
  1129. return k and issubclass(k, klasses)
  1130. return _integral_is_subclass
  1131. result = do_one(
  1132. null_safe(special_function_rule),
  1133. null_safe(switch(key, {
  1134. Pow: do_one(null_safe(power_rule), null_safe(inverse_trig_rule), \
  1135. null_safe(quadratic_denom_rule)),
  1136. Symbol: power_rule,
  1137. exp: exp_rule,
  1138. Add: add_rule,
  1139. Mul: do_one(null_safe(mul_rule), null_safe(trig_product_rule), \
  1140. null_safe(heaviside_rule), null_safe(quadratic_denom_rule), \
  1141. null_safe(root_mul_rule)),
  1142. Derivative: derivative_rule,
  1143. TrigonometricFunction: trig_rule,
  1144. Heaviside: heaviside_rule,
  1145. OrthogonalPolynomial: orthogonal_poly_rule,
  1146. Number: constant_rule
  1147. })),
  1148. do_one(
  1149. null_safe(trig_rule),
  1150. null_safe(alternatives(
  1151. rewrites_rule,
  1152. substitution_rule,
  1153. condition(
  1154. integral_is_subclass(Mul, Pow),
  1155. partial_fractions_rule),
  1156. condition(
  1157. integral_is_subclass(Mul, Pow),
  1158. cancel_rule),
  1159. condition(
  1160. integral_is_subclass(Mul, log,
  1161. *inverse_trig_functions),
  1162. parts_rule),
  1163. condition(
  1164. integral_is_subclass(Mul, Pow),
  1165. distribute_expand_rule),
  1166. trig_powers_products_rule,
  1167. trig_expand_rule
  1168. )),
  1169. null_safe(trig_substitution_rule)
  1170. ),
  1171. fallback_rule)(integral)
  1172. del _integral_cache[cachekey]
  1173. return result
  1174. @evaluates(ConstantRule)
  1175. def eval_constant(constant, integrand, symbol):
  1176. return constant * symbol
  1177. @evaluates(ConstantTimesRule)
  1178. def eval_constanttimes(constant, other, substep, integrand, symbol):
  1179. return constant * _manualintegrate(substep)
  1180. @evaluates(PowerRule)
  1181. def eval_power(base, exp, integrand, symbol):
  1182. return Piecewise(
  1183. ((base**(exp + 1))/(exp + 1), Ne(exp, -1)),
  1184. (log(base), True),
  1185. )
  1186. @evaluates(ExpRule)
  1187. def eval_exp(base, exp, integrand, symbol):
  1188. return integrand / log(base)
  1189. @evaluates(AddRule)
  1190. def eval_add(substeps, integrand, symbol):
  1191. return sum(map(_manualintegrate, substeps))
  1192. @evaluates(URule)
  1193. def eval_u(u_var, u_func, constant, substep, integrand, symbol):
  1194. result = _manualintegrate(substep)
  1195. if u_func.is_Pow and u_func.exp == -1:
  1196. # avoid needless -log(1/x) from substitution
  1197. result = result.subs(log(u_var), -log(u_func.base))
  1198. return result.subs(u_var, u_func)
  1199. @evaluates(PartsRule)
  1200. def eval_parts(u, dv, v_step, second_step, integrand, symbol):
  1201. v = _manualintegrate(v_step)
  1202. return u * v - _manualintegrate(second_step)
  1203. @evaluates(CyclicPartsRule)
  1204. def eval_cyclicparts(parts_rules, coefficient, integrand, symbol):
  1205. coefficient = 1 - coefficient
  1206. result = []
  1207. sign = 1
  1208. for rule in parts_rules:
  1209. result.append(sign * rule.u * _manualintegrate(rule.v_step))
  1210. sign *= -1
  1211. return Add(*result) / coefficient
  1212. @evaluates(TrigRule)
  1213. def eval_trig(func, arg, integrand, symbol):
  1214. if func == 'sin':
  1215. return -cos(arg)
  1216. elif func == 'cos':
  1217. return sin(arg)
  1218. elif func == 'sec*tan':
  1219. return sec(arg)
  1220. elif func == 'csc*cot':
  1221. return csc(arg)
  1222. elif func == 'sec**2':
  1223. return tan(arg)
  1224. elif func == 'csc**2':
  1225. return -cot(arg)
  1226. @evaluates(ArctanRule)
  1227. def eval_arctan(a, b, c, integrand, symbol):
  1228. return a / b * 1 / sqrt(c / b) * atan(symbol / sqrt(c / b))
  1229. @evaluates(ArccothRule)
  1230. def eval_arccoth(a, b, c, integrand, symbol):
  1231. return - a / b * 1 / sqrt(-c / b) * acoth(symbol / sqrt(-c / b))
  1232. @evaluates(ArctanhRule)
  1233. def eval_arctanh(a, b, c, integrand, symbol):
  1234. return - a / b * 1 / sqrt(-c / b) * atanh(symbol / sqrt(-c / b))
  1235. @evaluates(ReciprocalRule)
  1236. def eval_reciprocal(func, integrand, symbol):
  1237. return log(func)
  1238. @evaluates(ArcsinRule)
  1239. def eval_arcsin(integrand, symbol):
  1240. return asin(symbol)
  1241. @evaluates(InverseHyperbolicRule)
  1242. def eval_inversehyperbolic(func, integrand, symbol):
  1243. return func(symbol)
  1244. @evaluates(AlternativeRule)
  1245. def eval_alternative(alternatives, integrand, symbol):
  1246. return _manualintegrate(alternatives[0])
  1247. @evaluates(RewriteRule)
  1248. def eval_rewrite(rewritten, substep, integrand, symbol):
  1249. return _manualintegrate(substep)
  1250. @evaluates(PiecewiseRule)
  1251. def eval_piecewise(substeps, integrand, symbol):
  1252. return Piecewise(*[(_manualintegrate(substep), cond)
  1253. for substep, cond in substeps])
  1254. @evaluates(TrigSubstitutionRule)
  1255. def eval_trigsubstitution(theta, func, rewritten, substep, restriction, integrand, symbol):
  1256. func = func.subs(sec(theta), 1/cos(theta))
  1257. func = func.subs(csc(theta), 1/sin(theta))
  1258. func = func.subs(cot(theta), 1/tan(theta))
  1259. trig_function = list(func.find(TrigonometricFunction))
  1260. assert len(trig_function) == 1
  1261. trig_function = trig_function[0]
  1262. relation = solve(symbol - func, trig_function)
  1263. assert len(relation) == 1
  1264. numer, denom = fraction(relation[0])
  1265. if isinstance(trig_function, sin):
  1266. opposite = numer
  1267. hypotenuse = denom
  1268. adjacent = sqrt(denom**2 - numer**2)
  1269. inverse = asin(relation[0])
  1270. elif isinstance(trig_function, cos):
  1271. adjacent = numer
  1272. hypotenuse = denom
  1273. opposite = sqrt(denom**2 - numer**2)
  1274. inverse = acos(relation[0])
  1275. elif isinstance(trig_function, tan):
  1276. opposite = numer
  1277. adjacent = denom
  1278. hypotenuse = sqrt(denom**2 + numer**2)
  1279. inverse = atan(relation[0])
  1280. substitution = [
  1281. (sin(theta), opposite/hypotenuse),
  1282. (cos(theta), adjacent/hypotenuse),
  1283. (tan(theta), opposite/adjacent),
  1284. (theta, inverse)
  1285. ]
  1286. return Piecewise(
  1287. (_manualintegrate(substep).subs(substitution).trigsimp(), restriction)
  1288. )
  1289. @evaluates(DerivativeRule)
  1290. def eval_derivativerule(integrand, symbol):
  1291. # isinstance(integrand, Derivative) should be True
  1292. variable_count = list(integrand.variable_count)
  1293. for i, (var, count) in enumerate(variable_count):
  1294. if var == symbol:
  1295. variable_count[i] = (var, count-1)
  1296. break
  1297. return Derivative(integrand.expr, *variable_count)
  1298. @evaluates(HeavisideRule)
  1299. def eval_heaviside(harg, ibnd, substep, integrand, symbol):
  1300. # If we are integrating over x and the integrand has the form
  1301. # Heaviside(m*x+b)*g(x) == Heaviside(harg)*g(symbol)
  1302. # then there needs to be continuity at -b/m == ibnd,
  1303. # so we subtract the appropriate term.
  1304. return Heaviside(harg)*(substep - substep.subs(symbol, ibnd))
  1305. @evaluates(JacobiRule)
  1306. def eval_jacobi(n, a, b, integrand, symbol):
  1307. return Piecewise(
  1308. (2*jacobi(n + 1, a - 1, b - 1, symbol)/(n + a + b), Ne(n + a + b, 0)),
  1309. (symbol, Eq(n, 0)),
  1310. ((a + b + 2)*symbol**2/4 + (a - b)*symbol/2, Eq(n, 1)))
  1311. @evaluates(GegenbauerRule)
  1312. def eval_gegenbauer(n, a, integrand, symbol):
  1313. return Piecewise(
  1314. (gegenbauer(n + 1, a - 1, symbol)/(2*(a - 1)), Ne(a, 1)),
  1315. (chebyshevt(n + 1, symbol)/(n + 1), Ne(n, -1)),
  1316. (S.Zero, True))
  1317. @evaluates(ChebyshevTRule)
  1318. def eval_chebyshevt(n, integrand, symbol):
  1319. return Piecewise(((chebyshevt(n + 1, symbol)/(n + 1) -
  1320. chebyshevt(n - 1, symbol)/(n - 1))/2, Ne(Abs(n), 1)),
  1321. (symbol**2/2, True))
  1322. @evaluates(ChebyshevURule)
  1323. def eval_chebyshevu(n, integrand, symbol):
  1324. return Piecewise(
  1325. (chebyshevt(n + 1, symbol)/(n + 1), Ne(n, -1)),
  1326. (S.Zero, True))
  1327. @evaluates(LegendreRule)
  1328. def eval_legendre(n, integrand, symbol):
  1329. return (legendre(n + 1, symbol) - legendre(n - 1, symbol))/(2*n + 1)
  1330. @evaluates(HermiteRule)
  1331. def eval_hermite(n, integrand, symbol):
  1332. return hermite(n + 1, symbol)/(2*(n + 1))
  1333. @evaluates(LaguerreRule)
  1334. def eval_laguerre(n, integrand, symbol):
  1335. return laguerre(n, symbol) - laguerre(n + 1, symbol)
  1336. @evaluates(AssocLaguerreRule)
  1337. def eval_assoclaguerre(n, a, integrand, symbol):
  1338. return -assoc_laguerre(n + 1, a - 1, symbol)
  1339. @evaluates(CiRule)
  1340. def eval_ci(a, b, integrand, symbol):
  1341. return cos(b)*Ci(a*symbol) - sin(b)*Si(a*symbol)
  1342. @evaluates(ChiRule)
  1343. def eval_chi(a, b, integrand, symbol):
  1344. return cosh(b)*Chi(a*symbol) + sinh(b)*Shi(a*symbol)
  1345. @evaluates(EiRule)
  1346. def eval_ei(a, b, integrand, symbol):
  1347. return exp(b)*Ei(a*symbol)
  1348. @evaluates(SiRule)
  1349. def eval_si(a, b, integrand, symbol):
  1350. return sin(b)*Ci(a*symbol) + cos(b)*Si(a*symbol)
  1351. @evaluates(ShiRule)
  1352. def eval_shi(a, b, integrand, symbol):
  1353. return sinh(b)*Chi(a*symbol) + cosh(b)*Shi(a*symbol)
  1354. @evaluates(ErfRule)
  1355. def eval_erf(a, b, c, integrand, symbol):
  1356. if a.is_extended_real:
  1357. return Piecewise(
  1358. (sqrt(S.Pi/(-a))/2 * exp(c - b**2/(4*a)) *
  1359. erf((-2*a*symbol - b)/(2*sqrt(-a))), a < 0),
  1360. (sqrt(S.Pi/a)/2 * exp(c - b**2/(4*a)) *
  1361. erfi((2*a*symbol + b)/(2*sqrt(a))), True))
  1362. else:
  1363. return sqrt(S.Pi/a)/2 * exp(c - b**2/(4*a)) * \
  1364. erfi((2*a*symbol + b)/(2*sqrt(a)))
  1365. @evaluates(FresnelCRule)
  1366. def eval_fresnelc(a, b, c, integrand, symbol):
  1367. return sqrt(S.Pi/(2*a)) * (
  1368. cos(b**2/(4*a) - c)*fresnelc((2*a*symbol + b)/sqrt(2*a*S.Pi)) +
  1369. sin(b**2/(4*a) - c)*fresnels((2*a*symbol + b)/sqrt(2*a*S.Pi)))
  1370. @evaluates(FresnelSRule)
  1371. def eval_fresnels(a, b, c, integrand, symbol):
  1372. return sqrt(S.Pi/(2*a)) * (
  1373. cos(b**2/(4*a) - c)*fresnels((2*a*symbol + b)/sqrt(2*a*S.Pi)) -
  1374. sin(b**2/(4*a) - c)*fresnelc((2*a*symbol + b)/sqrt(2*a*S.Pi)))
  1375. @evaluates(LiRule)
  1376. def eval_li(a, b, integrand, symbol):
  1377. return li(a*symbol + b)/a
  1378. @evaluates(PolylogRule)
  1379. def eval_polylog(a, b, integrand, symbol):
  1380. return polylog(b + 1, a*symbol)
  1381. @evaluates(UpperGammaRule)
  1382. def eval_uppergamma(a, e, integrand, symbol):
  1383. return symbol**e * (-a*symbol)**(-e) * uppergamma(e + 1, -a*symbol)/a
  1384. @evaluates(EllipticFRule)
  1385. def eval_elliptic_f(a, d, integrand, symbol):
  1386. return elliptic_f(symbol, d/a)/sqrt(a)
  1387. @evaluates(EllipticERule)
  1388. def eval_elliptic_e(a, d, integrand, symbol):
  1389. return elliptic_e(symbol, d/a)*sqrt(a)
  1390. @evaluates(DontKnowRule)
  1391. def eval_dontknowrule(integrand, symbol):
  1392. return Integral(integrand, symbol)
  1393. def _manualintegrate(rule):
  1394. evaluator = evaluators.get(rule.__class__)
  1395. if not evaluator:
  1396. raise ValueError("Cannot evaluate rule %s" % repr(rule))
  1397. return evaluator(*rule)
  1398. def manualintegrate(f, var):
  1399. """manualintegrate(f, var)
  1400. Explanation
  1401. ===========
  1402. Compute indefinite integral of a single variable using an algorithm that
  1403. resembles what a student would do by hand.
  1404. Unlike :func:`~.integrate`, var can only be a single symbol.
  1405. Examples
  1406. ========
  1407. >>> from sympy import sin, cos, tan, exp, log, integrate
  1408. >>> from sympy.integrals.manualintegrate import manualintegrate
  1409. >>> from sympy.abc import x
  1410. >>> manualintegrate(1 / x, x)
  1411. log(x)
  1412. >>> integrate(1/x)
  1413. log(x)
  1414. >>> manualintegrate(log(x), x)
  1415. x*log(x) - x
  1416. >>> integrate(log(x))
  1417. x*log(x) - x
  1418. >>> manualintegrate(exp(x) / (1 + exp(2 * x)), x)
  1419. atan(exp(x))
  1420. >>> integrate(exp(x) / (1 + exp(2 * x)))
  1421. RootSum(4*_z**2 + 1, Lambda(_i, _i*log(2*_i + exp(x))))
  1422. >>> manualintegrate(cos(x)**4 * sin(x), x)
  1423. -cos(x)**5/5
  1424. >>> integrate(cos(x)**4 * sin(x), x)
  1425. -cos(x)**5/5
  1426. >>> manualintegrate(cos(x)**4 * sin(x)**3, x)
  1427. cos(x)**7/7 - cos(x)**5/5
  1428. >>> integrate(cos(x)**4 * sin(x)**3, x)
  1429. cos(x)**7/7 - cos(x)**5/5
  1430. >>> manualintegrate(tan(x), x)
  1431. -log(cos(x))
  1432. >>> integrate(tan(x), x)
  1433. -log(cos(x))
  1434. See Also
  1435. ========
  1436. sympy.integrals.integrals.integrate
  1437. sympy.integrals.integrals.Integral.doit
  1438. sympy.integrals.integrals.Integral
  1439. """
  1440. result = _manualintegrate(integral_steps(f, var))
  1441. # Clear the cache of u-parts
  1442. _parts_u_cache.clear()
  1443. # If we got Piecewise with two parts, put generic first
  1444. if isinstance(result, Piecewise) and len(result.args) == 2:
  1445. cond = result.args[0][1]
  1446. if isinstance(cond, Eq) and result.args[1][1] == True:
  1447. result = result.func(
  1448. (result.args[1][0], Ne(*cond.args)),
  1449. (result.args[0][0], True))
  1450. return result