transforms.py 89 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789
  1. """ Integral Transforms """
  2. from functools import reduce, wraps
  3. from itertools import repeat
  4. from sympy.core import S, pi, I
  5. from sympy.core.add import Add
  6. from sympy.core.function import (AppliedUndef, count_ops, Derivative, expand,
  7. expand_complex, expand_mul, Function, Lambda,
  8. WildFunction)
  9. from sympy.core.mul import Mul
  10. from sympy.core.numbers import igcd, ilcm
  11. from sympy.core.relational import _canonical, Ge, Gt, Lt, Unequality, Eq
  12. from sympy.core.sorting import default_sort_key, ordered
  13. from sympy.core.symbol import Dummy, symbols, Wild
  14. from sympy.core.traversal import postorder_traversal
  15. from sympy.functions.combinatorial.factorials import factorial, rf
  16. from sympy.functions.elementary.complexes import (re, arg, Abs, polar_lift,
  17. periodic_argument)
  18. from sympy.functions.elementary.exponential import exp, log, exp_polar
  19. from sympy.functions.elementary.hyperbolic import cosh, coth, sinh, tanh, asinh
  20. from sympy.functions.elementary.integers import ceiling
  21. from sympy.functions.elementary.miscellaneous import Max, Min, sqrt
  22. from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold
  23. from sympy.functions.elementary.trigonometric import cos, cot, sin, tan, atan
  24. from sympy.functions.special.bessel import besseli, besselj, besselk, bessely
  25. from sympy.functions.special.delta_functions import DiracDelta, Heaviside
  26. from sympy.functions.special.error_functions import erf, erfc, Ei
  27. from sympy.functions.special.gamma_functions import digamma, gamma, lowergamma
  28. from sympy.functions.special.hyper import meijerg
  29. from sympy.integrals import integrate, Integral
  30. from sympy.integrals.meijerint import _dummy
  31. from sympy.logic.boolalg import to_cnf, conjuncts, disjuncts, Or, And
  32. from sympy.matrices.matrices import MatrixBase
  33. from sympy.polys.matrices.linsolve import _lin_eq2dict, PolyNonlinearError
  34. from sympy.polys.polyroots import roots
  35. from sympy.polys.polytools import factor, Poly
  36. from sympy.polys.rationaltools import together
  37. from sympy.polys.rootoftools import CRootOf, RootSum
  38. from sympy.simplify import simplify, hyperexpand
  39. from sympy.simplify.powsimp import powdenest
  40. from sympy.solvers.inequalities import _solve_inequality
  41. from sympy.utilities.exceptions import (sympy_deprecation_warning,
  42. SymPyDeprecationWarning,
  43. ignore_warnings)
  44. from sympy.utilities.iterables import iterable
  45. from sympy.utilities.misc import debug
  46. ##########################################################################
  47. # Helpers / Utilities
  48. ##########################################################################
  49. class IntegralTransformError(NotImplementedError):
  50. """
  51. Exception raised in relation to problems computing transforms.
  52. Explanation
  53. ===========
  54. This class is mostly used internally; if integrals cannot be computed
  55. objects representing unevaluated transforms are usually returned.
  56. The hint ``needeval=True`` can be used to disable returning transform
  57. objects, and instead raise this exception if an integral cannot be
  58. computed.
  59. """
  60. def __init__(self, transform, function, msg):
  61. super().__init__(
  62. "%s Transform could not be computed: %s." % (transform, msg))
  63. self.function = function
  64. class IntegralTransform(Function):
  65. """
  66. Base class for integral transforms.
  67. Explanation
  68. ===========
  69. This class represents unevaluated transforms.
  70. To implement a concrete transform, derive from this class and implement
  71. the ``_compute_transform(f, x, s, **hints)`` and ``_as_integral(f, x, s)``
  72. functions. If the transform cannot be computed, raise :obj:`IntegralTransformError`.
  73. Also set ``cls._name``. For instance,
  74. >>> from sympy import LaplaceTransform
  75. >>> LaplaceTransform._name
  76. 'Laplace'
  77. Implement ``self._collapse_extra`` if your function returns more than just a
  78. number and possibly a convergence condition.
  79. """
  80. @property
  81. def function(self):
  82. """ The function to be transformed. """
  83. return self.args[0]
  84. @property
  85. def function_variable(self):
  86. """ The dependent variable of the function to be transformed. """
  87. return self.args[1]
  88. @property
  89. def transform_variable(self):
  90. """ The independent transform variable. """
  91. return self.args[2]
  92. @property
  93. def free_symbols(self):
  94. """
  95. This method returns the symbols that will exist when the transform
  96. is evaluated.
  97. """
  98. return self.function.free_symbols.union({self.transform_variable}) \
  99. - {self.function_variable}
  100. def _compute_transform(self, f, x, s, **hints):
  101. raise NotImplementedError
  102. def _as_integral(self, f, x, s):
  103. raise NotImplementedError
  104. def _collapse_extra(self, extra):
  105. cond = And(*extra)
  106. if cond == False:
  107. raise IntegralTransformError(self.__class__.name, None, '')
  108. return cond
  109. def _try_directly(self, **hints):
  110. T = None
  111. try_directly = not any(func.has(self.function_variable)
  112. for func in self.function.atoms(AppliedUndef))
  113. if try_directly:
  114. try:
  115. T = self._compute_transform(self.function,
  116. self.function_variable, self.transform_variable, **hints)
  117. except IntegralTransformError:
  118. T = None
  119. fn = self.function
  120. if not fn.is_Add:
  121. fn = expand_mul(fn)
  122. return fn, T
  123. def doit(self, **hints):
  124. """
  125. Try to evaluate the transform in closed form.
  126. Explanation
  127. ===========
  128. This general function handles linearity, but apart from that leaves
  129. pretty much everything to _compute_transform.
  130. Standard hints are the following:
  131. - ``simplify``: whether or not to simplify the result
  132. - ``noconds``: if True, do not return convergence conditions
  133. - ``needeval``: if True, raise IntegralTransformError instead of
  134. returning IntegralTransform objects
  135. The default values of these hints depend on the concrete transform,
  136. usually the default is
  137. ``(simplify, noconds, needeval) = (True, False, False)``.
  138. """
  139. needeval = hints.pop('needeval', False)
  140. simplify = hints.pop('simplify', True)
  141. hints['simplify'] = simplify
  142. fn, T = self._try_directly(**hints)
  143. if T is not None:
  144. return T
  145. if fn.is_Add:
  146. hints['needeval'] = needeval
  147. res = [self.__class__(*([x] + list(self.args[1:]))).doit(**hints)
  148. for x in fn.args]
  149. extra = []
  150. ress = []
  151. for x in res:
  152. if not isinstance(x, tuple):
  153. x = [x]
  154. ress.append(x[0])
  155. if len(x) == 2:
  156. # only a condition
  157. extra.append(x[1])
  158. elif len(x) > 2:
  159. # some region parameters and a condition (Mellin, Laplace)
  160. extra += [x[1:]]
  161. if simplify==True:
  162. res = Add(*ress).simplify()
  163. else:
  164. res = Add(*ress)
  165. if not extra:
  166. return res
  167. try:
  168. extra = self._collapse_extra(extra)
  169. if iterable(extra):
  170. return tuple([res]) + tuple(extra)
  171. else:
  172. return (res, extra)
  173. except IntegralTransformError:
  174. pass
  175. if needeval:
  176. raise IntegralTransformError(
  177. self.__class__._name, self.function, 'needeval')
  178. # TODO handle derivatives etc
  179. # pull out constant coefficients
  180. coeff, rest = fn.as_coeff_mul(self.function_variable)
  181. return coeff*self.__class__(*([Mul(*rest)] + list(self.args[1:])))
  182. @property
  183. def as_integral(self):
  184. return self._as_integral(self.function, self.function_variable,
  185. self.transform_variable)
  186. def _eval_rewrite_as_Integral(self, *args, **kwargs):
  187. return self.as_integral
  188. def _simplify(expr, doit):
  189. if doit:
  190. return simplify(powdenest(piecewise_fold(expr), polar=True))
  191. return expr
  192. def _noconds_(default):
  193. """
  194. This is a decorator generator for dropping convergence conditions.
  195. Explanation
  196. ===========
  197. Suppose you define a function ``transform(*args)`` which returns a tuple of
  198. the form ``(result, cond1, cond2, ...)``.
  199. Decorating it ``@_noconds_(default)`` will add a new keyword argument
  200. ``noconds`` to it. If ``noconds=True``, the return value will be altered to
  201. be only ``result``, whereas if ``noconds=False`` the return value will not
  202. be altered.
  203. The default value of the ``noconds`` keyword will be ``default`` (i.e. the
  204. argument of this function).
  205. """
  206. def make_wrapper(func):
  207. @wraps(func)
  208. def wrapper(*args, noconds=default, **kwargs):
  209. res = func(*args, **kwargs)
  210. if noconds:
  211. return res[0]
  212. return res
  213. return wrapper
  214. return make_wrapper
  215. _noconds = _noconds_(False)
  216. ##########################################################################
  217. # Mellin Transform
  218. ##########################################################################
  219. def _default_integrator(f, x):
  220. return integrate(f, (x, S.Zero, S.Infinity))
  221. @_noconds
  222. def _mellin_transform(f, x, s_, integrator=_default_integrator, simplify=True):
  223. """ Backend function to compute Mellin transforms. """
  224. # We use a fresh dummy, because assumptions on s might drop conditions on
  225. # convergence of the integral.
  226. s = _dummy('s', 'mellin-transform', f)
  227. F = integrator(x**(s - 1) * f, x)
  228. if not F.has(Integral):
  229. return _simplify(F.subs(s, s_), simplify), (S.NegativeInfinity, S.Infinity), S.true
  230. if not F.is_Piecewise: # XXX can this work if integration gives continuous result now?
  231. raise IntegralTransformError('Mellin', f, 'could not compute integral')
  232. F, cond = F.args[0]
  233. if F.has(Integral):
  234. raise IntegralTransformError(
  235. 'Mellin', f, 'integral in unexpected form')
  236. def process_conds(cond):
  237. """
  238. Turn ``cond`` into a strip (a, b), and auxiliary conditions.
  239. """
  240. a = S.NegativeInfinity
  241. b = S.Infinity
  242. aux = S.true
  243. conds = conjuncts(to_cnf(cond))
  244. t = Dummy('t', real=True)
  245. for c in conds:
  246. a_ = S.Infinity
  247. b_ = S.NegativeInfinity
  248. aux_ = []
  249. for d in disjuncts(c):
  250. d_ = d.replace(
  251. re, lambda x: x.as_real_imag()[0]).subs(re(s), t)
  252. if not d.is_Relational or \
  253. d.rel_op in ('==', '!=') \
  254. or d_.has(s) or not d_.has(t):
  255. aux_ += [d]
  256. continue
  257. soln = _solve_inequality(d_, t)
  258. if not soln.is_Relational or \
  259. soln.rel_op in ('==', '!='):
  260. aux_ += [d]
  261. continue
  262. if soln.lts == t:
  263. b_ = Max(soln.gts, b_)
  264. else:
  265. a_ = Min(soln.lts, a_)
  266. if a_ is not S.Infinity and a_ != b:
  267. a = Max(a_, a)
  268. elif b_ is not S.NegativeInfinity and b_ != a:
  269. b = Min(b_, b)
  270. else:
  271. aux = And(aux, Or(*aux_))
  272. return a, b, aux
  273. conds = [process_conds(c) for c in disjuncts(cond)]
  274. conds = [x for x in conds if x[2] != False]
  275. conds.sort(key=lambda x: (x[0] - x[1], count_ops(x[2])))
  276. if not conds:
  277. raise IntegralTransformError('Mellin', f, 'no convergence found')
  278. a, b, aux = conds[0]
  279. return _simplify(F.subs(s, s_), simplify), (a, b), aux
  280. class MellinTransform(IntegralTransform):
  281. """
  282. Class representing unevaluated Mellin transforms.
  283. For usage of this class, see the :class:`IntegralTransform` docstring.
  284. For how to compute Mellin transforms, see the :func:`mellin_transform`
  285. docstring.
  286. """
  287. _name = 'Mellin'
  288. def _compute_transform(self, f, x, s, **hints):
  289. return _mellin_transform(f, x, s, **hints)
  290. def _as_integral(self, f, x, s):
  291. return Integral(f*x**(s - 1), (x, S.Zero, S.Infinity))
  292. def _collapse_extra(self, extra):
  293. a = []
  294. b = []
  295. cond = []
  296. for (sa, sb), c in extra:
  297. a += [sa]
  298. b += [sb]
  299. cond += [c]
  300. res = (Max(*a), Min(*b)), And(*cond)
  301. if (res[0][0] >= res[0][1]) == True or res[1] == False:
  302. raise IntegralTransformError(
  303. 'Mellin', None, 'no combined convergence.')
  304. return res
  305. def mellin_transform(f, x, s, **hints):
  306. r"""
  307. Compute the Mellin transform `F(s)` of `f(x)`,
  308. .. math :: F(s) = \int_0^\infty x^{s-1} f(x) \mathrm{d}x.
  309. For all "sensible" functions, this converges absolutely in a strip
  310. `a < \operatorname{Re}(s) < b`.
  311. Explanation
  312. ===========
  313. The Mellin transform is related via change of variables to the Fourier
  314. transform, and also to the (bilateral) Laplace transform.
  315. This function returns ``(F, (a, b), cond)``
  316. where ``F`` is the Mellin transform of ``f``, ``(a, b)`` is the fundamental strip
  317. (as above), and ``cond`` are auxiliary convergence conditions.
  318. If the integral cannot be computed in closed form, this function returns
  319. an unevaluated :class:`MellinTransform` object.
  320. For a description of possible hints, refer to the docstring of
  321. :func:`sympy.integrals.transforms.IntegralTransform.doit`. If ``noconds=False``,
  322. then only `F` will be returned (i.e. not ``cond``, and also not the strip
  323. ``(a, b)``).
  324. Examples
  325. ========
  326. >>> from sympy import mellin_transform, exp
  327. >>> from sympy.abc import x, s
  328. >>> mellin_transform(exp(-x), x, s)
  329. (gamma(s), (0, oo), True)
  330. See Also
  331. ========
  332. inverse_mellin_transform, laplace_transform, fourier_transform
  333. hankel_transform, inverse_hankel_transform
  334. """
  335. return MellinTransform(f, x, s).doit(**hints)
  336. def _rewrite_sin(m_n, s, a, b):
  337. """
  338. Re-write the sine function ``sin(m*s + n)`` as gamma functions, compatible
  339. with the strip (a, b).
  340. Return ``(gamma1, gamma2, fac)`` so that ``f == fac/(gamma1 * gamma2)``.
  341. Examples
  342. ========
  343. >>> from sympy.integrals.transforms import _rewrite_sin
  344. >>> from sympy import pi, S
  345. >>> from sympy.abc import s
  346. >>> _rewrite_sin((pi, 0), s, 0, 1)
  347. (gamma(s), gamma(1 - s), pi)
  348. >>> _rewrite_sin((pi, 0), s, 1, 0)
  349. (gamma(s - 1), gamma(2 - s), -pi)
  350. >>> _rewrite_sin((pi, 0), s, -1, 0)
  351. (gamma(s + 1), gamma(-s), -pi)
  352. >>> _rewrite_sin((pi, pi/2), s, S(1)/2, S(3)/2)
  353. (gamma(s - 1/2), gamma(3/2 - s), -pi)
  354. >>> _rewrite_sin((pi, pi), s, 0, 1)
  355. (gamma(s), gamma(1 - s), -pi)
  356. >>> _rewrite_sin((2*pi, 0), s, 0, S(1)/2)
  357. (gamma(2*s), gamma(1 - 2*s), pi)
  358. >>> _rewrite_sin((2*pi, 0), s, S(1)/2, 1)
  359. (gamma(2*s - 1), gamma(2 - 2*s), -pi)
  360. """
  361. # (This is a separate function because it is moderately complicated,
  362. # and I want to doctest it.)
  363. # We want to use pi/sin(pi*x) = gamma(x)*gamma(1-x).
  364. # But there is one comlication: the gamma functions determine the
  365. # inegration contour in the definition of the G-function. Usually
  366. # it would not matter if this is slightly shifted, unless this way
  367. # we create an undefined function!
  368. # So we try to write this in such a way that the gammas are
  369. # eminently on the right side of the strip.
  370. m, n = m_n
  371. m = expand_mul(m/pi)
  372. n = expand_mul(n/pi)
  373. r = ceiling(-m*a - n.as_real_imag()[0]) # Don't use re(n), does not expand
  374. return gamma(m*s + n + r), gamma(1 - n - r - m*s), (-1)**r*pi
  375. class MellinTransformStripError(ValueError):
  376. """
  377. Exception raised by _rewrite_gamma. Mainly for internal use.
  378. """
  379. pass
  380. def _rewrite_gamma(f, s, a, b):
  381. """
  382. Try to rewrite the product f(s) as a product of gamma functions,
  383. so that the inverse Mellin transform of f can be expressed as a meijer
  384. G function.
  385. Explanation
  386. ===========
  387. Return (an, ap), (bm, bq), arg, exp, fac such that
  388. G((an, ap), (bm, bq), arg/z**exp)*fac is the inverse Mellin transform of f(s).
  389. Raises IntegralTransformError or MellinTransformStripError on failure.
  390. It is asserted that f has no poles in the fundamental strip designated by
  391. (a, b). One of a and b is allowed to be None. The fundamental strip is
  392. important, because it determines the inversion contour.
  393. This function can handle exponentials, linear factors, trigonometric
  394. functions.
  395. This is a helper function for inverse_mellin_transform that will not
  396. attempt any transformations on f.
  397. Examples
  398. ========
  399. >>> from sympy.integrals.transforms import _rewrite_gamma
  400. >>> from sympy.abc import s
  401. >>> from sympy import oo
  402. >>> _rewrite_gamma(s*(s+3)*(s-1), s, -oo, oo)
  403. (([], [-3, 0, 1]), ([-2, 1, 2], []), 1, 1, -1)
  404. >>> _rewrite_gamma((s-1)**2, s, -oo, oo)
  405. (([], [1, 1]), ([2, 2], []), 1, 1, 1)
  406. Importance of the fundamental strip:
  407. >>> _rewrite_gamma(1/s, s, 0, oo)
  408. (([1], []), ([], [0]), 1, 1, 1)
  409. >>> _rewrite_gamma(1/s, s, None, oo)
  410. (([1], []), ([], [0]), 1, 1, 1)
  411. >>> _rewrite_gamma(1/s, s, 0, None)
  412. (([1], []), ([], [0]), 1, 1, 1)
  413. >>> _rewrite_gamma(1/s, s, -oo, 0)
  414. (([], [1]), ([0], []), 1, 1, -1)
  415. >>> _rewrite_gamma(1/s, s, None, 0)
  416. (([], [1]), ([0], []), 1, 1, -1)
  417. >>> _rewrite_gamma(1/s, s, -oo, None)
  418. (([], [1]), ([0], []), 1, 1, -1)
  419. >>> _rewrite_gamma(2**(-s+3), s, -oo, oo)
  420. (([], []), ([], []), 1/2, 1, 8)
  421. """
  422. # Our strategy will be as follows:
  423. # 1) Guess a constant c such that the inversion integral should be
  424. # performed wrt s'=c*s (instead of plain s). Write s for s'.
  425. # 2) Process all factors, rewrite them independently as gamma functions in
  426. # argument s, or exponentials of s.
  427. # 3) Try to transform all gamma functions s.t. they have argument
  428. # a+s or a-s.
  429. # 4) Check that the resulting G function parameters are valid.
  430. # 5) Combine all the exponentials.
  431. a_, b_ = S([a, b])
  432. def left(c, is_numer):
  433. """
  434. Decide whether pole at c lies to the left of the fundamental strip.
  435. """
  436. # heuristically, this is the best chance for us to solve the inequalities
  437. c = expand(re(c))
  438. if a_ is None and b_ is S.Infinity:
  439. return True
  440. if a_ is None:
  441. return c < b_
  442. if b_ is None:
  443. return c <= a_
  444. if (c >= b_) == True:
  445. return False
  446. if (c <= a_) == True:
  447. return True
  448. if is_numer:
  449. return None
  450. if a_.free_symbols or b_.free_symbols or c.free_symbols:
  451. return None # XXX
  452. #raise IntegralTransformError('Inverse Mellin', f,
  453. # 'Could not determine position of singularity %s'
  454. # ' relative to fundamental strip' % c)
  455. raise MellinTransformStripError('Pole inside critical strip?')
  456. # 1)
  457. s_multipliers = []
  458. for g in f.atoms(gamma):
  459. if not g.has(s):
  460. continue
  461. arg = g.args[0]
  462. if arg.is_Add:
  463. arg = arg.as_independent(s)[1]
  464. coeff, _ = arg.as_coeff_mul(s)
  465. s_multipliers += [coeff]
  466. for g in f.atoms(sin, cos, tan, cot):
  467. if not g.has(s):
  468. continue
  469. arg = g.args[0]
  470. if arg.is_Add:
  471. arg = arg.as_independent(s)[1]
  472. coeff, _ = arg.as_coeff_mul(s)
  473. s_multipliers += [coeff/pi]
  474. s_multipliers = [Abs(x) if x.is_extended_real else x for x in s_multipliers]
  475. common_coefficient = S.One
  476. for x in s_multipliers:
  477. if not x.is_Rational:
  478. common_coefficient = x
  479. break
  480. s_multipliers = [x/common_coefficient for x in s_multipliers]
  481. if not (all(x.is_Rational for x in s_multipliers) and
  482. common_coefficient.is_extended_real):
  483. raise IntegralTransformError("Gamma", None, "Nonrational multiplier")
  484. s_multiplier = common_coefficient/reduce(ilcm, [S(x.q)
  485. for x in s_multipliers], S.One)
  486. if s_multiplier == common_coefficient:
  487. if len(s_multipliers) == 0:
  488. s_multiplier = common_coefficient
  489. else:
  490. s_multiplier = common_coefficient \
  491. *reduce(igcd, [S(x.p) for x in s_multipliers])
  492. f = f.subs(s, s/s_multiplier)
  493. fac = S.One/s_multiplier
  494. exponent = S.One/s_multiplier
  495. if a_ is not None:
  496. a_ *= s_multiplier
  497. if b_ is not None:
  498. b_ *= s_multiplier
  499. # 2)
  500. numer, denom = f.as_numer_denom()
  501. numer = Mul.make_args(numer)
  502. denom = Mul.make_args(denom)
  503. args = list(zip(numer, repeat(True))) + list(zip(denom, repeat(False)))
  504. facs = []
  505. dfacs = []
  506. # *_gammas will contain pairs (a, c) representing Gamma(a*s + c)
  507. numer_gammas = []
  508. denom_gammas = []
  509. # exponentials will contain bases for exponentials of s
  510. exponentials = []
  511. def exception(fact):
  512. return IntegralTransformError("Inverse Mellin", f, "Unrecognised form '%s'." % fact)
  513. while args:
  514. fact, is_numer = args.pop()
  515. if is_numer:
  516. ugammas, lgammas = numer_gammas, denom_gammas
  517. ufacs = facs
  518. else:
  519. ugammas, lgammas = denom_gammas, numer_gammas
  520. ufacs = dfacs
  521. def linear_arg(arg):
  522. """ Test if arg is of form a*s+b, raise exception if not. """
  523. if not arg.is_polynomial(s):
  524. raise exception(fact)
  525. p = Poly(arg, s)
  526. if p.degree() != 1:
  527. raise exception(fact)
  528. return p.all_coeffs()
  529. # constants
  530. if not fact.has(s):
  531. ufacs += [fact]
  532. # exponentials
  533. elif fact.is_Pow or isinstance(fact, exp):
  534. if fact.is_Pow:
  535. base = fact.base
  536. exp_ = fact.exp
  537. else:
  538. base = exp_polar(1)
  539. exp_ = fact.exp
  540. if exp_.is_Integer:
  541. cond = is_numer
  542. if exp_ < 0:
  543. cond = not cond
  544. args += [(base, cond)]*Abs(exp_)
  545. continue
  546. elif not base.has(s):
  547. a, b = linear_arg(exp_)
  548. if not is_numer:
  549. base = 1/base
  550. exponentials += [base**a]
  551. facs += [base**b]
  552. else:
  553. raise exception(fact)
  554. # linear factors
  555. elif fact.is_polynomial(s):
  556. p = Poly(fact, s)
  557. if p.degree() != 1:
  558. # We completely factor the poly. For this we need the roots.
  559. # Now roots() only works in some cases (low degree), and CRootOf
  560. # only works without parameters. So try both...
  561. coeff = p.LT()[1]
  562. rs = roots(p, s)
  563. if len(rs) != p.degree():
  564. rs = CRootOf.all_roots(p)
  565. ufacs += [coeff]
  566. args += [(s - c, is_numer) for c in rs]
  567. continue
  568. a, c = p.all_coeffs()
  569. ufacs += [a]
  570. c /= -a
  571. # Now need to convert s - c
  572. if left(c, is_numer):
  573. ugammas += [(S.One, -c + 1)]
  574. lgammas += [(S.One, -c)]
  575. else:
  576. ufacs += [-1]
  577. ugammas += [(S.NegativeOne, c + 1)]
  578. lgammas += [(S.NegativeOne, c)]
  579. elif isinstance(fact, gamma):
  580. a, b = linear_arg(fact.args[0])
  581. if is_numer:
  582. if (a > 0 and (left(-b/a, is_numer) == False)) or \
  583. (a < 0 and (left(-b/a, is_numer) == True)):
  584. raise NotImplementedError(
  585. 'Gammas partially over the strip.')
  586. ugammas += [(a, b)]
  587. elif isinstance(fact, sin):
  588. # We try to re-write all trigs as gammas. This is not in
  589. # general the best strategy, since sometimes this is impossible,
  590. # but rewriting as exponentials would work. However trig functions
  591. # in inverse mellin transforms usually all come from simplifying
  592. # gamma terms, so this should work.
  593. a = fact.args[0]
  594. if is_numer:
  595. # No problem with the poles.
  596. gamma1, gamma2, fac_ = gamma(a/pi), gamma(1 - a/pi), pi
  597. else:
  598. gamma1, gamma2, fac_ = _rewrite_sin(linear_arg(a), s, a_, b_)
  599. args += [(gamma1, not is_numer), (gamma2, not is_numer)]
  600. ufacs += [fac_]
  601. elif isinstance(fact, tan):
  602. a = fact.args[0]
  603. args += [(sin(a, evaluate=False), is_numer),
  604. (sin(pi/2 - a, evaluate=False), not is_numer)]
  605. elif isinstance(fact, cos):
  606. a = fact.args[0]
  607. args += [(sin(pi/2 - a, evaluate=False), is_numer)]
  608. elif isinstance(fact, cot):
  609. a = fact.args[0]
  610. args += [(sin(pi/2 - a, evaluate=False), is_numer),
  611. (sin(a, evaluate=False), not is_numer)]
  612. else:
  613. raise exception(fact)
  614. fac *= Mul(*facs)/Mul(*dfacs)
  615. # 3)
  616. an, ap, bm, bq = [], [], [], []
  617. for gammas, plus, minus, is_numer in [(numer_gammas, an, bm, True),
  618. (denom_gammas, bq, ap, False)]:
  619. while gammas:
  620. a, c = gammas.pop()
  621. if a != -1 and a != +1:
  622. # We use the gamma function multiplication theorem.
  623. p = Abs(S(a))
  624. newa = a/p
  625. newc = c/p
  626. if not a.is_Integer:
  627. raise TypeError("a is not an integer")
  628. for k in range(p):
  629. gammas += [(newa, newc + k/p)]
  630. if is_numer:
  631. fac *= (2*pi)**((1 - p)/2) * p**(c - S.Half)
  632. exponentials += [p**a]
  633. else:
  634. fac /= (2*pi)**((1 - p)/2) * p**(c - S.Half)
  635. exponentials += [p**(-a)]
  636. continue
  637. if a == +1:
  638. plus.append(1 - c)
  639. else:
  640. minus.append(c)
  641. # 4)
  642. # TODO
  643. # 5)
  644. arg = Mul(*exponentials)
  645. # for testability, sort the arguments
  646. an.sort(key=default_sort_key)
  647. ap.sort(key=default_sort_key)
  648. bm.sort(key=default_sort_key)
  649. bq.sort(key=default_sort_key)
  650. return (an, ap), (bm, bq), arg, exponent, fac
  651. @_noconds_(True)
  652. def _inverse_mellin_transform(F, s, x_, strip, as_meijerg=False):
  653. """ A helper for the real inverse_mellin_transform function, this one here
  654. assumes x to be real and positive. """
  655. x = _dummy('t', 'inverse-mellin-transform', F, positive=True)
  656. # Actually, we won't try integration at all. Instead we use the definition
  657. # of the Meijer G function as a fairly general inverse mellin transform.
  658. F = F.rewrite(gamma)
  659. for g in [factor(F), expand_mul(F), expand(F)]:
  660. if g.is_Add:
  661. # do all terms separately
  662. ress = [_inverse_mellin_transform(G, s, x, strip, as_meijerg,
  663. noconds=False)
  664. for G in g.args]
  665. conds = [p[1] for p in ress]
  666. ress = [p[0] for p in ress]
  667. res = Add(*ress)
  668. if not as_meijerg:
  669. res = factor(res, gens=res.atoms(Heaviside))
  670. return res.subs(x, x_), And(*conds)
  671. try:
  672. a, b, C, e, fac = _rewrite_gamma(g, s, strip[0], strip[1])
  673. except IntegralTransformError:
  674. continue
  675. try:
  676. G = meijerg(a, b, C/x**e)
  677. except ValueError:
  678. continue
  679. if as_meijerg:
  680. h = G
  681. else:
  682. try:
  683. h = hyperexpand(G)
  684. except NotImplementedError:
  685. raise IntegralTransformError(
  686. 'Inverse Mellin', F, 'Could not calculate integral')
  687. if h.is_Piecewise and len(h.args) == 3:
  688. # XXX we break modularity here!
  689. h = Heaviside(x - Abs(C))*h.args[0].args[0] \
  690. + Heaviside(Abs(C) - x)*h.args[1].args[0]
  691. # We must ensure that the integral along the line we want converges,
  692. # and return that value.
  693. # See [L], 5.2
  694. cond = [Abs(arg(G.argument)) < G.delta*pi]
  695. # Note: we allow ">=" here, this corresponds to convergence if we let
  696. # limits go to oo symmetrically. ">" corresponds to absolute convergence.
  697. cond += [And(Or(len(G.ap) != len(G.bq), 0 >= re(G.nu) + 1),
  698. Abs(arg(G.argument)) == G.delta*pi)]
  699. cond = Or(*cond)
  700. if cond == False:
  701. raise IntegralTransformError(
  702. 'Inverse Mellin', F, 'does not converge')
  703. return (h*fac).subs(x, x_), cond
  704. raise IntegralTransformError('Inverse Mellin', F, '')
  705. _allowed = None
  706. class InverseMellinTransform(IntegralTransform):
  707. """
  708. Class representing unevaluated inverse Mellin transforms.
  709. For usage of this class, see the :class:`IntegralTransform` docstring.
  710. For how to compute inverse Mellin transforms, see the
  711. :func:`inverse_mellin_transform` docstring.
  712. """
  713. _name = 'Inverse Mellin'
  714. _none_sentinel = Dummy('None')
  715. _c = Dummy('c')
  716. def __new__(cls, F, s, x, a, b, **opts):
  717. if a is None:
  718. a = InverseMellinTransform._none_sentinel
  719. if b is None:
  720. b = InverseMellinTransform._none_sentinel
  721. return IntegralTransform.__new__(cls, F, s, x, a, b, **opts)
  722. @property
  723. def fundamental_strip(self):
  724. a, b = self.args[3], self.args[4]
  725. if a is InverseMellinTransform._none_sentinel:
  726. a = None
  727. if b is InverseMellinTransform._none_sentinel:
  728. b = None
  729. return a, b
  730. def _compute_transform(self, F, s, x, **hints):
  731. # IntegralTransform's doit will cause this hint to exist, but
  732. # InverseMellinTransform should ignore it
  733. hints.pop('simplify', True)
  734. global _allowed
  735. if _allowed is None:
  736. _allowed = {
  737. exp, gamma, sin, cos, tan, cot, cosh, sinh, tanh, coth,
  738. factorial, rf}
  739. for f in postorder_traversal(F):
  740. if f.is_Function and f.has(s) and f.func not in _allowed:
  741. raise IntegralTransformError('Inverse Mellin', F,
  742. 'Component %s not recognised.' % f)
  743. strip = self.fundamental_strip
  744. return _inverse_mellin_transform(F, s, x, strip, **hints)
  745. def _as_integral(self, F, s, x):
  746. c = self.__class__._c
  747. return Integral(F*x**(-s), (s, c - S.ImaginaryUnit*S.Infinity, c +
  748. S.ImaginaryUnit*S.Infinity))/(2*S.Pi*S.ImaginaryUnit)
  749. def inverse_mellin_transform(F, s, x, strip, **hints):
  750. r"""
  751. Compute the inverse Mellin transform of `F(s)` over the fundamental
  752. strip given by ``strip=(a, b)``.
  753. Explanation
  754. ===========
  755. This can be defined as
  756. .. math:: f(x) = \frac{1}{2\pi i} \int_{c - i\infty}^{c + i\infty} x^{-s} F(s) \mathrm{d}s,
  757. for any `c` in the fundamental strip. Under certain regularity
  758. conditions on `F` and/or `f`,
  759. this recovers `f` from its Mellin transform `F`
  760. (and vice versa), for positive real `x`.
  761. One of `a` or `b` may be passed as ``None``; a suitable `c` will be
  762. inferred.
  763. If the integral cannot be computed in closed form, this function returns
  764. an unevaluated :class:`InverseMellinTransform` object.
  765. Note that this function will assume x to be positive and real, regardless
  766. of the SymPy assumptions!
  767. For a description of possible hints, refer to the docstring of
  768. :func:`sympy.integrals.transforms.IntegralTransform.doit`.
  769. Examples
  770. ========
  771. >>> from sympy import inverse_mellin_transform, oo, gamma
  772. >>> from sympy.abc import x, s
  773. >>> inverse_mellin_transform(gamma(s), s, x, (0, oo))
  774. exp(-x)
  775. The fundamental strip matters:
  776. >>> f = 1/(s**2 - 1)
  777. >>> inverse_mellin_transform(f, s, x, (-oo, -1))
  778. x*(1 - 1/x**2)*Heaviside(x - 1)/2
  779. >>> inverse_mellin_transform(f, s, x, (-1, 1))
  780. -x*Heaviside(1 - x)/2 - Heaviside(x - 1)/(2*x)
  781. >>> inverse_mellin_transform(f, s, x, (1, oo))
  782. (1/2 - x**2/2)*Heaviside(1 - x)/x
  783. See Also
  784. ========
  785. mellin_transform
  786. hankel_transform, inverse_hankel_transform
  787. """
  788. return InverseMellinTransform(F, s, x, strip[0], strip[1]).doit(**hints)
  789. ##########################################################################
  790. # Laplace Transform
  791. ##########################################################################
  792. def _simplifyconds(expr, s, a):
  793. r"""
  794. Naively simplify some conditions occurring in ``expr``, given that `\operatorname{Re}(s) > a`.
  795. Examples
  796. ========
  797. >>> from sympy.integrals.transforms import _simplifyconds as simp
  798. >>> from sympy.abc import x
  799. >>> from sympy import sympify as S
  800. >>> simp(abs(x**2) < 1, x, 1)
  801. False
  802. >>> simp(abs(x**2) < 1, x, 2)
  803. False
  804. >>> simp(abs(x**2) < 1, x, 0)
  805. Abs(x**2) < 1
  806. >>> simp(abs(1/x**2) < 1, x, 1)
  807. True
  808. >>> simp(S(1) < abs(x), x, 1)
  809. True
  810. >>> simp(S(1) < abs(1/x), x, 1)
  811. False
  812. >>> from sympy import Ne
  813. >>> simp(Ne(1, x**3), x, 1)
  814. True
  815. >>> simp(Ne(1, x**3), x, 2)
  816. True
  817. >>> simp(Ne(1, x**3), x, 0)
  818. Ne(1, x**3)
  819. """
  820. def power(ex):
  821. if ex == s:
  822. return 1
  823. if ex.is_Pow and ex.base == s:
  824. return ex.exp
  825. return None
  826. def bigger(ex1, ex2):
  827. """ Return True only if |ex1| > |ex2|, False only if |ex1| < |ex2|.
  828. Else return None. """
  829. if ex1.has(s) and ex2.has(s):
  830. return None
  831. if isinstance(ex1, Abs):
  832. ex1 = ex1.args[0]
  833. if isinstance(ex2, Abs):
  834. ex2 = ex2.args[0]
  835. if ex1.has(s):
  836. return bigger(1/ex2, 1/ex1)
  837. n = power(ex2)
  838. if n is None:
  839. return None
  840. try:
  841. if n > 0 and (Abs(ex1) <= Abs(a)**n) == True:
  842. return False
  843. if n < 0 and (Abs(ex1) >= Abs(a)**n) == True:
  844. return True
  845. except TypeError:
  846. pass
  847. def replie(x, y):
  848. """ simplify x < y """
  849. if not (x.is_positive or isinstance(x, Abs)) \
  850. or not (y.is_positive or isinstance(y, Abs)):
  851. return (x < y)
  852. r = bigger(x, y)
  853. if r is not None:
  854. return not r
  855. return (x < y)
  856. def replue(x, y):
  857. b = bigger(x, y)
  858. if b in (True, False):
  859. return True
  860. return Unequality(x, y)
  861. def repl(ex, *args):
  862. if ex in (True, False):
  863. return bool(ex)
  864. return ex.replace(*args)
  865. from sympy.simplify.radsimp import collect_abs
  866. expr = collect_abs(expr)
  867. expr = repl(expr, Lt, replie)
  868. expr = repl(expr, Gt, lambda x, y: replie(y, x))
  869. expr = repl(expr, Unequality, replue)
  870. return S(expr)
  871. def expand_dirac_delta(expr):
  872. """
  873. Expand an expression involving DiractDelta to get it as a linear
  874. combination of DiracDelta functions.
  875. """
  876. return _lin_eq2dict(expr, expr.atoms(DiracDelta))
  877. @_noconds
  878. def _laplace_transform(f, t, s_, simplify=True):
  879. """ The backend function for Laplace transforms.
  880. This backend assumes that the frontend has already split sums
  881. such that `f` is to an addition anymore.
  882. """
  883. s = Dummy('s')
  884. a = Wild('a', exclude=[t])
  885. deltazero = []
  886. deltanonzero = []
  887. try:
  888. integratable, deltadict = expand_dirac_delta(f)
  889. except PolyNonlinearError:
  890. raise IntegralTransformError(
  891. 'Laplace', f, 'could not expand DiracDelta expressions')
  892. for dirac_func, dirac_coeff in deltadict.items():
  893. p = dirac_func.match(DiracDelta(a*t))
  894. if p:
  895. deltazero.append(dirac_coeff.subs(t,0)/p[a])
  896. else:
  897. if dirac_func.args[0].subs(t,0).is_zero:
  898. raise IntegralTransformError('Laplace', f,\
  899. 'not implemented yet.')
  900. else:
  901. deltanonzero.append(dirac_func*dirac_coeff)
  902. F = Add(integrate(exp(-s*t) * Add(integratable, *deltanonzero),
  903. (t, S.Zero, S.Infinity)),
  904. Add(*deltazero))
  905. if not F.has(Integral):
  906. return _simplify(F.subs(s, s_), simplify), S.NegativeInfinity, S.true
  907. if not F.is_Piecewise:
  908. raise IntegralTransformError(
  909. 'Laplace', f, 'could not compute integral')
  910. F, cond = F.args[0]
  911. if F.has(Integral):
  912. raise IntegralTransformError(
  913. 'Laplace', f, 'integral in unexpected form')
  914. def process_conds(conds):
  915. """ Turn ``conds`` into a strip and auxiliary conditions. """
  916. a = S.NegativeInfinity
  917. aux = S.true
  918. conds = conjuncts(to_cnf(conds))
  919. p, q, w1, w2, w3, w4, w5 = symbols(
  920. 'p q w1 w2 w3 w4 w5', cls=Wild, exclude=[s])
  921. patterns = (
  922. p*Abs(arg((s + w3)*q)) < w2,
  923. p*Abs(arg((s + w3)*q)) <= w2,
  924. Abs(periodic_argument((s + w3)**p*q, w1)) < w2,
  925. Abs(periodic_argument((s + w3)**p*q, w1)) <= w2,
  926. Abs(periodic_argument((polar_lift(s + w3))**p*q, w1)) < w2,
  927. Abs(periodic_argument((polar_lift(s + w3))**p*q, w1)) <= w2)
  928. for c in conds:
  929. a_ = S.Infinity
  930. aux_ = []
  931. for d in disjuncts(c):
  932. if d.is_Relational and s in d.rhs.free_symbols:
  933. d = d.reversed
  934. if d.is_Relational and isinstance(d, (Ge, Gt)):
  935. d = d.reversedsign
  936. for pat in patterns:
  937. m = d.match(pat)
  938. if m:
  939. break
  940. if m:
  941. if m[q].is_positive and m[w2]/m[p] == pi/2:
  942. d = -re(s + m[w3]) < 0
  943. m = d.match(p - cos(w1*Abs(arg(s*w5))*w2)*Abs(s**w3)**w4 < 0)
  944. if not m:
  945. m = d.match(
  946. cos(p - Abs(periodic_argument(s**w1*w5, q))*w2)*Abs(s**w3)**w4 < 0)
  947. if not m:
  948. m = d.match(
  949. p - cos(Abs(periodic_argument(polar_lift(s)**w1*w5, q))*w2
  950. )*Abs(s**w3)**w4 < 0)
  951. if m and all(m[wild].is_positive for wild in [w1, w2, w3, w4, w5]):
  952. d = re(s) > m[p]
  953. d_ = d.replace(
  954. re, lambda x: x.expand().as_real_imag()[0]).subs(re(s), t)
  955. if not d.is_Relational or \
  956. d.rel_op in ('==', '!=') \
  957. or d_.has(s) or not d_.has(t):
  958. aux_ += [d]
  959. continue
  960. soln = _solve_inequality(d_, t)
  961. if not soln.is_Relational or \
  962. soln.rel_op in ('==', '!='):
  963. aux_ += [d]
  964. continue
  965. if soln.lts == t:
  966. raise IntegralTransformError('Laplace', f,
  967. 'convergence not in half-plane?')
  968. else:
  969. a_ = Min(soln.lts, a_)
  970. if a_ is not S.Infinity:
  971. a = Max(a_, a)
  972. else:
  973. aux = And(aux, Or(*aux_))
  974. return a, aux.canonical if aux.is_Relational else aux
  975. conds = [process_conds(c) for c in disjuncts(cond)]
  976. conds2 = [x for x in conds if x[1] != False and x[0] is not S.NegativeInfinity]
  977. if not conds2:
  978. conds2 = [x for x in conds if x[1] != False]
  979. conds = list(ordered(conds2))
  980. def cnt(expr):
  981. if expr in (True, False):
  982. return 0
  983. return expr.count_ops()
  984. conds.sort(key=lambda x: (-x[0], cnt(x[1])))
  985. if not conds:
  986. raise IntegralTransformError('Laplace', f, 'no convergence found')
  987. a, aux = conds[0] # XXX is [0] always the right one?
  988. def sbs(expr):
  989. return expr.subs(s, s_)
  990. if simplify:
  991. F = _simplifyconds(F, s, a)
  992. aux = _simplifyconds(aux, s, a)
  993. return _simplify(F.subs(s, s_), simplify), sbs(a), _canonical(sbs(aux))
  994. def _laplace_deep_collect(f, t):
  995. """
  996. This is an internal helper function that traverses through the epression
  997. tree of `f(t)` and collects arguments. The purpose of it is that
  998. anything like `f(w*t-1*t-c)` will be written as `f((w-1)*t-c)` such that
  999. it can match `f(a*t+b)`.
  1000. """
  1001. func = f.func
  1002. args = list(f.args)
  1003. if len(f.args) == 0:
  1004. return f
  1005. else:
  1006. for k in range(len(args)):
  1007. args[k] = _laplace_deep_collect(args[k], t)
  1008. if func.is_Add:
  1009. return func(*args).collect(t)
  1010. else:
  1011. return func(*args)
  1012. def _laplace_build_rules(t, s):
  1013. """
  1014. This is an internal helper function that returns the table of Laplace
  1015. transfrom rules in terms of the time variable `t` and the frequency
  1016. variable `s`. It is used by `_laplace_apply_rules`.
  1017. """
  1018. a = Wild('a', exclude=[t])
  1019. b = Wild('b', exclude=[t])
  1020. n = Wild('n', exclude=[t])
  1021. tau = Wild('tau', exclude=[t])
  1022. omega = Wild('omega', exclude=[t])
  1023. dco = lambda f: _laplace_deep_collect(f,t)
  1024. laplace_transform_rules = [
  1025. # ( time domain,
  1026. # laplace domain,
  1027. # condition, convergence plane, preparation function )
  1028. #
  1029. # Catch constant (would otherwise be treated by 2.12)
  1030. (a, a/s, S.true, S.Zero, dco),
  1031. # DiracDelta rules
  1032. (DiracDelta(a*t-b),
  1033. exp(-s*b/a)/Abs(a),
  1034. Or(And(a>0, b>=0), And(a<0, b<=0)), S.Zero, dco),
  1035. (DiracDelta(a*t-b),
  1036. S(0),
  1037. Or(And(a<0, b>=0), And(a>0, b<=0)), S.Zero, dco),
  1038. # Rules from http://eqworld.ipmnet.ru/en/auxiliary/inttrans/
  1039. # 2.1
  1040. (1,
  1041. 1/s,
  1042. S.true, S.Zero, dco),
  1043. # 2.2 expressed in terms of Heaviside
  1044. (Heaviside(a*t-b),
  1045. exp(-s*b/a)/s,
  1046. And(a>0, b>0), S.Zero, dco),
  1047. (Heaviside(a*t-b),
  1048. (1-exp(-s*b/a))/s,
  1049. And(a<0, b<0), S.Zero, dco),
  1050. (Heaviside(a*t-b),
  1051. 1/s,
  1052. And(a>0, b<=0), S.Zero, dco),
  1053. (Heaviside(a*t-b),
  1054. 0,
  1055. And(a<0, b>0), S.Zero, dco),
  1056. # 2.3
  1057. (t,
  1058. 1/s**2,
  1059. S.true, S.Zero, dco),
  1060. # 2.4
  1061. (1/(a*t+b),
  1062. -exp(-b/a*s)*Ei(-b/a*s)/a,
  1063. a>0, S.Zero, dco),
  1064. # 2.5 and 2.6 are covered by 2.11
  1065. # 2.7
  1066. (1/sqrt(a*t+b),
  1067. sqrt(a*pi/s)*exp(b/a*s)*erfc(sqrt(b/a*s))/a,
  1068. a>0, S.Zero, dco),
  1069. # 2.8
  1070. (sqrt(t)/(t+b),
  1071. sqrt(pi/s)-pi*sqrt(b)*exp(b*s)*erfc(sqrt(b*s)),
  1072. S.true, S.Zero, dco),
  1073. # 2.9
  1074. ((a*t+b)**(-S(3)/2),
  1075. 2*b**(-S(1)/2)-2*(pi*s/a)**(S(1)/2)*exp(b/a*s)*erfc(sqrt(b/a*s))/a,
  1076. a>0, S.Zero, dco),
  1077. # 2.10
  1078. (t**(S(1)/2)*(t+a)**(-1),
  1079. (pi/s)**(S(1)/2)-pi*a**(S(1)/2)*exp(a*s)*erfc(sqrt(a*s)),
  1080. S.true, S.Zero, dco),
  1081. # 2.11
  1082. (1/(a*sqrt(t) + t**(3/2)),
  1083. pi*a**(S(1)/2)*exp(a*s)*erfc(sqrt(a*s)),
  1084. S.true, S.Zero, dco),
  1085. # 2.12
  1086. (t**n,
  1087. gamma(n+1)/s**(n+1),
  1088. n>-1, S.Zero, dco),
  1089. # 2.13
  1090. ((a*t+b)**n,
  1091. lowergamma(n+1, b/a*s)*exp(-b/a*s)/s**(n+1)/a,
  1092. And(n>-1, a>0), S.Zero, dco),
  1093. # 2.14
  1094. (t**n/(t+a),
  1095. a**n*gamma(n+1)*lowergamma(-n,a*s),
  1096. n>-1, S.Zero, dco),
  1097. # 3.1
  1098. (exp(a*t-tau),
  1099. exp(-tau)/(s-a),
  1100. S.true, a, dco),
  1101. # 3.2
  1102. (t*exp(a*t-tau),
  1103. exp(-tau)/(s-a)**2,
  1104. S.true, a, dco),
  1105. # 3.3
  1106. (t**n*exp(a*t),
  1107. gamma(n+1)/(s-a)**(n+1),
  1108. n>-1, a, dco),
  1109. # 3.4 and 3.5 cannot be covered here because they are
  1110. # sums and only the individual sum terms will get here.
  1111. # 3.6
  1112. (exp(-a*t**2),
  1113. sqrt(pi/4/a)*exp(s**2/4/a)*erfc(s/sqrt(4*a)),
  1114. a>0, S.Zero, dco),
  1115. # 3.7
  1116. (t*exp(-a*t**2),
  1117. 1/(2*a)-2/sqrt(pi)/(4*a)**(S(3)/2)*s*erfc(s/sqrt(4*a)),
  1118. S.true, S.Zero, dco),
  1119. # 3.8
  1120. (exp(-a/t),
  1121. 2*sqrt(a/s)*besselk(1, 2*sqrt(a*s)),
  1122. a>=0, S.Zero, dco),
  1123. # 3.9
  1124. (sqrt(t)*exp(-a/t),
  1125. S(1)/2*sqrt(pi/s**3)*(1+2*sqrt(a*s))*exp(-2*sqrt(a*s)),
  1126. a>=0, S.Zero, dco),
  1127. # 3.10
  1128. (exp(-a/t)/sqrt(t),
  1129. sqrt(pi/s)*exp(-2*sqrt(a*s)),
  1130. a>=0, S.Zero, dco),
  1131. # 3.11
  1132. (exp(-a/t)/(t*sqrt(t)),
  1133. sqrt(pi/a)*exp(-2*sqrt(a*s)),
  1134. a>0, S.Zero, dco),
  1135. # 3.12
  1136. (t**n*exp(-a/t),
  1137. 2*(a/s)**((n+1)/2)*besselk(n+1, 2*sqrt(a*s)),
  1138. a>0, S.Zero, dco),
  1139. # 3.13
  1140. (exp(-2*sqrt(a*t)),
  1141. s**(-1)-sqrt(pi*a)*s**(-S(3)/2)*exp(a/s)*erfc(sqrt(a/s)),
  1142. S.true, S.Zero, dco),
  1143. # 3.14
  1144. (exp(-2*sqrt(a*t))/sqrt(t),
  1145. (pi/s)**(S(1)/2)*exp(a/s)*erfc(sqrt(a/s)),
  1146. S.true, S.Zero, dco),
  1147. # 4.1
  1148. (sinh(a*t),
  1149. a/(s**2-a**2),
  1150. S.true, Abs(a), dco),
  1151. # 4.2
  1152. (sinh(a*t)**2,
  1153. 2*a**2/(s**3-4*a**2*s**2),
  1154. S.true, Abs(2*a), dco),
  1155. # 4.3
  1156. (sinh(a*t)/t,
  1157. log((s+a)/(s-a))/2,
  1158. S.true, a, dco),
  1159. # 4.4
  1160. (t**n*sinh(a*t),
  1161. gamma(n+1)/2*((s-a)**(-n-1)-(s+a)**(-n-1)),
  1162. n>-2, Abs(a), dco),
  1163. # 4.5
  1164. (sinh(2*sqrt(a*t)),
  1165. sqrt(pi*a)/s/sqrt(s)*exp(a/s),
  1166. S.true, S.Zero, dco),
  1167. # 4.6
  1168. (sqrt(t)*sinh(2*sqrt(a*t)),
  1169. pi**(S(1)/2)*s**(-S(5)/2)*(s/2+a)*exp(a/s)*erf(sqrt(a/s))-a**(S(1)/2)*s**(-2),
  1170. S.true, S.Zero, dco),
  1171. # 4.7
  1172. (sinh(2*sqrt(a*t))/sqrt(t),
  1173. pi**(S(1)/2)*s**(-S(1)/2)*exp(a/s)*erf(sqrt(a/s)),
  1174. S.true, S.Zero, dco),
  1175. # 4.8
  1176. (sinh(sqrt(a*t))**2/sqrt(t),
  1177. pi**(S(1)/2)/2*s**(-S(1)/2)*(exp(a/s)-1),
  1178. S.true, S.Zero, dco),
  1179. # 4.9
  1180. (cosh(a*t),
  1181. s/(s**2-a**2),
  1182. S.true, Abs(a), dco),
  1183. # 4.10
  1184. (cosh(a*t)**2,
  1185. (s**2-2*a**2)/(s**3-4*a**2*s**2),
  1186. S.true, Abs(2*a), dco),
  1187. # 4.11
  1188. (t**n*cosh(a*t),
  1189. gamma(n+1)/2*((s-a)**(-n-1)+(s+a)**(-n-1)),
  1190. n>-1, Abs(a), dco),
  1191. # 4.12
  1192. (cosh(2*sqrt(a*t)),
  1193. 1/s+sqrt(pi*a)/s/sqrt(s)*exp(a/s)*erf(sqrt(a/s)),
  1194. S.true, S.Zero, dco),
  1195. # 4.13
  1196. (sqrt(t)*cosh(2*sqrt(a*t)),
  1197. pi**(S(1)/2)*s**(-S(5)/2)*(s/2+a)*exp(a/s),
  1198. S.true, S.Zero, dco),
  1199. # 4.14
  1200. (cosh(2*sqrt(a*t))/sqrt(t),
  1201. pi**(S(1)/2)*s**(-S(1)/2)*exp(a/s),
  1202. S.true, S.Zero, dco),
  1203. # 4.15
  1204. (cosh(sqrt(a*t))**2/sqrt(t),
  1205. pi**(S(1)/2)/2*s**(-S(1)/2)*(exp(a/s)+1),
  1206. S.true, S.Zero, dco),
  1207. # 5.1
  1208. (log(a*t),
  1209. -log(s/a+S.EulerGamma)/s,
  1210. a>0, S.Zero, dco),
  1211. # 5.2
  1212. (log(1+a*t),
  1213. -exp(s/a)/s*Ei(-s/a),
  1214. S.true, S.Zero, dco),
  1215. # 5.3
  1216. (log(a*t+b),
  1217. (log(b)-exp(s/b/a)/s*a*Ei(-s/b))/s*a,
  1218. a>0, S.Zero, dco),
  1219. # 5.4 is covered by 5.7
  1220. # 5.5
  1221. (log(t)/sqrt(t),
  1222. -sqrt(pi/s)*(log(4*s)+S.EulerGamma),
  1223. S.true, S.Zero, dco),
  1224. # 5.6 is covered by 5.7
  1225. # 5.7
  1226. (t**n*log(t),
  1227. gamma(n+1)*s**(-n-1)*(digamma(n+1)-log(s)),
  1228. n>-1, S.Zero, dco),
  1229. # 5.8
  1230. (log(a*t)**2,
  1231. ((log(s/a)+S.EulerGamma)**2+pi**2/6)/s,
  1232. a>0, S.Zero, dco),
  1233. # 5.9
  1234. (exp(-a*t)*log(t),
  1235. -(log(s+a)+S.EulerGamma)/(s+a),
  1236. S.true, -a, dco),
  1237. # 6.1
  1238. (sin(omega*t),
  1239. omega/(s**2+omega**2),
  1240. S.true, S.Zero, dco),
  1241. # 6.2
  1242. (Abs(sin(omega*t)),
  1243. omega/(s**2+omega**2)*coth(pi*s/2/omega),
  1244. omega>0, S.Zero, dco),
  1245. # 6.3 and 6.4 are covered by 1.8
  1246. # 6.5 is covered by 1.8 together with 2.5
  1247. # 6.6
  1248. (sin(omega*t)/t,
  1249. atan(omega/s),
  1250. S.true, S.Zero, dco),
  1251. # 6.7
  1252. (sin(omega*t)**2/t,
  1253. log(1+4*omega**2/s**2)/4,
  1254. S.true, S.Zero, dco),
  1255. # 6.8
  1256. (sin(omega*t)**2/t**2,
  1257. omega*atan(2*omega/s)-s*log(1+4*omega**2/s**2)/4,
  1258. S.true, S.Zero, dco),
  1259. # 6.9
  1260. (sin(2*sqrt(a*t)),
  1261. sqrt(pi*a)/s/sqrt(s)*exp(-a/s),
  1262. a>0, S.Zero, dco),
  1263. # 6.10
  1264. (sin(2*sqrt(a*t))/t,
  1265. pi*erf(sqrt(a/s)),
  1266. a>0, S.Zero, dco),
  1267. # 6.11
  1268. (cos(omega*t),
  1269. s/(s**2+omega**2),
  1270. S.true, S.Zero, dco),
  1271. # 6.12
  1272. (cos(omega*t)**2,
  1273. (s**2+2*omega**2)/(s**2+4*omega**2)/s,
  1274. S.true, S.Zero, dco),
  1275. # 6.13 is covered by 1.9 together with 2.5
  1276. # 6.14 and 6.15 cannot be done with this method, the respective sum
  1277. # parts do not converge. Solve elsewhere if really needed.
  1278. # 6.16
  1279. (sqrt(t)*cos(2*sqrt(a*t)),
  1280. sqrt(pi)/2*s**(-S(5)/2)*(s-2*a)*exp(-a/s),
  1281. a>0, S.Zero, dco),
  1282. # 6.17
  1283. (cos(2*sqrt(a*t))/sqrt(t),
  1284. sqrt(pi/s)*exp(-a/s),
  1285. a>0, S.Zero, dco),
  1286. # 6.18
  1287. (sin(a*t)*sin(b*t),
  1288. 2*a*b*s/(s**2+(a+b)**2)/(s**2+(a-b)**2),
  1289. S.true, S.Zero, dco),
  1290. # 6.19
  1291. (cos(a*t)*sin(b*t),
  1292. b*(s**2-a**2+b**2)/(s**2+(a+b)**2)/(s**2+(a-b)**2),
  1293. S.true, S.Zero, dco),
  1294. # 6.20
  1295. (cos(a*t)*cos(b*t),
  1296. s*(s**2+a**2+b**2)/(s**2+(a+b)**2)/(s**2+(a-b)**2),
  1297. S.true, S.Zero, dco),
  1298. # 6.21
  1299. (exp(b*t)*sin(a*t),
  1300. a/((s-b)**2+a**2),
  1301. S.true, b, dco),
  1302. # 6.22
  1303. (exp(b*t)*cos(a*t),
  1304. (s-b)/((s-b)**2+a**2),
  1305. S.true, b, dco),
  1306. # 7.1
  1307. (erf(a*t),
  1308. exp(s**2/(2*a)**2)*erfc(s/(2*a))/s,
  1309. a>0, S.Zero, dco),
  1310. # 7.2
  1311. (erf(sqrt(a*t)),
  1312. sqrt(a)/sqrt(s+a)/s,
  1313. a>0, S.Zero, dco),
  1314. # 7.3
  1315. (exp(a*t)*erf(sqrt(a*t)),
  1316. sqrt(a)/sqrt(s)/(s-a),
  1317. a>0, a, dco),
  1318. # 7.4
  1319. (erf(sqrt(a/t)/2),
  1320. (1-exp(-sqrt(a*s)))/s,
  1321. a>0, S.Zero, dco),
  1322. # 7.5
  1323. (erfc(sqrt(a*t)),
  1324. (sqrt(s+a)-sqrt(a))/sqrt(s+a)/s,
  1325. a>0, S.Zero, dco),
  1326. # 7.6
  1327. (exp(a*t)*erfc(sqrt(a*t)),
  1328. 1/(s+sqrt(a*s)),
  1329. a>0, S.Zero, dco),
  1330. # 7.7
  1331. (erfc(sqrt(a/t)/2),
  1332. exp(-sqrt(a*s))/s,
  1333. a>0, S.Zero, dco),
  1334. # 8.1, 8.2
  1335. (besselj(n, a*t),
  1336. a**n/(sqrt(s**2+a**2)*(s+sqrt(s**2+a**2))**n),
  1337. And(a>0, n>-1), S.Zero, dco),
  1338. # 8.3, 8.4
  1339. (t**b*besselj(n, a*t),
  1340. 2**n/sqrt(pi)*gamma(n+S.Half)*a**n*(s**2+a**2)**(-n-S.Half),
  1341. And(And(a>0, n>-S.Half), Eq(b, n)), S.Zero, dco),
  1342. # 8.5
  1343. (t**b*besselj(n, a*t),
  1344. 2**(n+1)/sqrt(pi)*gamma(n+S(3)/2)*a**n*s*(s**2+a**2)**(-n-S(3)/2),
  1345. And(And(a>0, n>-1), Eq(b, n+1)), S.Zero, dco),
  1346. # 8.6
  1347. (besselj(0, 2*sqrt(a*t)),
  1348. exp(-a/s)/s,
  1349. a>0, S.Zero, dco),
  1350. # 8.7, 8.8
  1351. (t**(b)*besselj(n, 2*sqrt(a*t)),
  1352. a**(n/2)*s**(-n-1)*exp(-a/s),
  1353. And(And(a>0, n>-1), Eq(b, n*S.Half)), S.Zero, dco),
  1354. # 8.9
  1355. (besselj(0, a*sqrt(t**2+b*t)),
  1356. exp(b*s-b*sqrt(s**2+a**2))/sqrt(s**2+a**2),
  1357. b>0, S.Zero, dco),
  1358. # 8.10, 8.11
  1359. (besseli(n, a*t),
  1360. a**n/(sqrt(s**2-a**2)*(s+sqrt(s**2-a**2))**n),
  1361. And(a>0, n>-1), Abs(a), dco),
  1362. # 8.12
  1363. (t**b*besseli(n, a*t),
  1364. 2**n/sqrt(pi)*gamma(n+S.Half)*a**n*(s**2-a**2)**(-n-S.Half),
  1365. And(And(a>0, n>-S.Half), Eq(b, n)), Abs(a), dco),
  1366. # 8.13
  1367. (t**b*besseli(n, a*t),
  1368. 2**(n+1)/sqrt(pi)*gamma(n+S(3)/2)*a**n*s*(s**2-a**2)**(-n-S(3)/2),
  1369. And(And(a>0, n>-1), Eq(b, n+1)), Abs(a), dco),
  1370. # 8.15, 8.16
  1371. (t**(b)*besseli(n, 2*sqrt(a*t)),
  1372. a**(n/2)*s**(-n-1)*exp(a/s),
  1373. And(And(a>0, n>-1), Eq(b, n*S.Half)), S.Zero, dco),
  1374. # 8.17
  1375. (bessely(0, a*t),
  1376. -2/pi*asinh(s/a)/sqrt(s**2+a**2),
  1377. a>0, S.Zero, dco),
  1378. # 8.18
  1379. (besselk(0, a*t),
  1380. (log(s+sqrt(s**2-a**2)))/(sqrt(s**2-a**2)),
  1381. a>0, Abs(a), dco)
  1382. ]
  1383. return laplace_transform_rules
  1384. def _laplace_cr(f, a, c, **hints):
  1385. """
  1386. Internal helper function that will return `(f, a, c)` unless `**hints`
  1387. contains `noconds=True`, in which case it will only return `f`.
  1388. """
  1389. conds = not hints.get('noconds', False)
  1390. if conds:
  1391. return f, a, c
  1392. else:
  1393. return f
  1394. def _laplace_rule_timescale(f, t, s, doit=True, **hints):
  1395. r"""
  1396. This internal helper function tries to apply the time-scaling rule of the
  1397. Laplace transform and returns `None` if it cannot do it.
  1398. Time-scaling means the following: if $F(s)$ is the Laplace transform of,
  1399. $f(t)$, then, for any $a>0$, the Laplace transform of $f(at)$ will be
  1400. $\frac1a F(\frac{s}{a})$. This scaling will also affect the transform's
  1401. convergence plane.
  1402. """
  1403. _simplify = hints.pop('simplify', True)
  1404. b = Wild('b', exclude=[t])
  1405. g = WildFunction('g', nargs=1)
  1406. k, func = f.as_independent(t, as_Add=False)
  1407. ma1 = func.match(g)
  1408. if ma1:
  1409. arg = ma1[g].args[0].collect(t)
  1410. ma2 = arg.match(b*t)
  1411. if ma2 and ma2[b]>0:
  1412. debug('_laplace_apply_rules match:')
  1413. debug(' f: %s ( %s, %s )'%(f, ma1, ma2))
  1414. debug(' rule: amplitude and time scaling (1.1, 1.2)')
  1415. if ma2[b]==1:
  1416. if doit==True and not any(func.has(t) for func
  1417. in ma1[g].atoms(AppliedUndef)):
  1418. return k*_laplace_transform(ma1[g].func(t), t, s,
  1419. simplify=_simplify)
  1420. else:
  1421. return k*LaplaceTransform(ma1[g].func(t), t, s, **hints)
  1422. else:
  1423. L = _laplace_apply_rules(ma1[g].func(t), t, s/ma2[b],
  1424. doit=doit, **hints)
  1425. try:
  1426. r, p, c = L
  1427. return (k/ma2[b]*r, p, c)
  1428. except TypeError:
  1429. return k/ma2[b]*L
  1430. return None
  1431. def _laplace_rule_heaviside(f, t, s, doit=True, **hints):
  1432. """
  1433. This internal helper function tries to transform a product containing the
  1434. `Heaviside` function and returns `None` if it cannot do it.
  1435. """
  1436. hints.pop('simplify', True)
  1437. a = Wild('a', exclude=[t])
  1438. b = Wild('b', exclude=[t])
  1439. y = Wild('y')
  1440. g = WildFunction('g', nargs=1)
  1441. k, func = f.as_independent(t, as_Add=False)
  1442. ma1 = func.match(Heaviside(y)*g)
  1443. if ma1:
  1444. ma2 = ma1[y].match(t-a)
  1445. ma3 = ma1[g].args[0].collect(t).match(t-b)
  1446. if ma2 and ma2[a]>0 and ma3 and ma2[a]==ma3[b]:
  1447. debug('_laplace_apply_rules match:')
  1448. debug(' f: %s ( %s, %s, %s )'%(f, ma1, ma2, ma3))
  1449. debug(' rule: time shift (1.3)')
  1450. L = _laplace_apply_rules(ma1[g].func(t), t, s, doit=doit, **hints)
  1451. try:
  1452. r, p, c = L
  1453. return (k*exp(-ma2[a]*s)*r, p, c)
  1454. except TypeError:
  1455. return k*exp(-ma2[a]*s)*L
  1456. return None
  1457. def _laplace_rule_exp(f, t, s, doit=True, **hints):
  1458. """
  1459. This internal helper function tries to transform a product containing the
  1460. `exp` function and returns `None` if it cannot do it.
  1461. """
  1462. hints.pop('simplify', True)
  1463. a = Wild('a', exclude=[t])
  1464. y = Wild('y')
  1465. z = Wild('z')
  1466. k, func = f.as_independent(t, as_Add=False)
  1467. ma1 = func.match(exp(y)*z)
  1468. if ma1:
  1469. ma2 = ma1[y].collect(t).match(a*t)
  1470. if ma2:
  1471. debug('_laplace_apply_rules match:')
  1472. debug(' f: %s ( %s, %s )'%(f, ma1, ma2))
  1473. debug(' rule: multiply with exp (1.5)')
  1474. L = _laplace_apply_rules(ma1[z], t, s-ma2[a], doit=doit, **hints)
  1475. try:
  1476. r, p, c = L
  1477. return (r, p+ma2[a], c)
  1478. except TypeError:
  1479. return L
  1480. return None
  1481. def _laplace_rule_trig(f, t, s, doit=True, **hints):
  1482. """
  1483. This internal helper function tries to transform a product containing a
  1484. trigonometric function (`sin`, `cos`, `sinh`, `cosh`, ) and returns
  1485. `None` if it cannot do it.
  1486. """
  1487. _simplify = hints.pop('simplify', True)
  1488. a = Wild('a', exclude=[t])
  1489. y = Wild('y')
  1490. z = Wild('z')
  1491. k, func = f.as_independent(t, as_Add=False)
  1492. # All of the rules have a very similar form: trig(y)*z is matched, and then
  1493. # two copies of the Laplace transform of z are shifted in the s Domain
  1494. # and added with a weight; see rules 1.6 to 1.9 in
  1495. # http://eqworld.ipmnet.ru/en/auxiliary/inttrans/laplace1.pdf
  1496. # The parameters in the tuples are (fm, nu, s1, s2, sd):
  1497. # fm: Function to match
  1498. # nu: Number of the rule, for debug purposes
  1499. # s1: weight of the sum, 'I' for sin and '1' for all others
  1500. # s2: sign of the second copy of the Laplace transform of z
  1501. # sd: shift direction; shift along real or imaginary axis if `1` or `I`
  1502. trigrules = [(sinh(y), '1.6', 1, -1, 1), (cosh(y), '1.7', 1, 1, 1),
  1503. (sin(y), '1.8', -I, -1, I), (cos(y), '1.9', 1, 1, I)]
  1504. for trigrule in trigrules:
  1505. fm, nu, s1, s2, sd = trigrule
  1506. ma1 = func.match(fm*z)
  1507. if ma1:
  1508. ma2 = ma1[y].collect(t).match(a*t)
  1509. if ma2:
  1510. debug('_laplace_apply_rules match:')
  1511. debug(' f: %s ( %s, %s )'%(f, ma1, ma2))
  1512. debug(' rule: multiply with %s (%s)'%(fm.func, nu))
  1513. L = _laplace_apply_rules(ma1[z], t, s, doit=doit, **hints)
  1514. try:
  1515. r, p, c = L
  1516. # The convergence plane changes only if the shift has been
  1517. # done along the real axis:
  1518. if sd==1:
  1519. cp_shift = Abs(ma2[a])
  1520. else:
  1521. cp_shift = 0
  1522. return ((s1*(r.subs(s, s-sd*ma2[a])+\
  1523. s2*r.subs(s, s+sd*ma2[a]))).simplify()/2,
  1524. p+cp_shift, c)
  1525. except TypeError:
  1526. if doit==True and _simplify==True:
  1527. return (s1*(L.subs(s, s-sd*ma2[a])+\
  1528. s2*L.subs(s, s+sd*ma2[a]))).simplify()/2
  1529. else:
  1530. return (s1*(L.subs(s, s-sd*ma2[a])+\
  1531. s2*L.subs(s, s+sd*ma2[a])))/2
  1532. return None
  1533. def _laplace_rule_diff(f, t, s, doit=True, **hints):
  1534. """
  1535. This internal helper function tries to transform an expression containing
  1536. a derivative of an undefined function and returns `None` if it cannot
  1537. do it.
  1538. """
  1539. hints.pop('simplify', True)
  1540. a = Wild('a', exclude=[t])
  1541. y = Wild('y')
  1542. n = Wild('n', exclude=[t])
  1543. g = WildFunction('g', nargs=1)
  1544. ma1 = f.match(a*Derivative(g, (t, n)))
  1545. if ma1 and ma1[g].args[0] == t and ma1[n].is_integer:
  1546. debug('_laplace_apply_rules match:')
  1547. debug(' f: %s'%(f,))
  1548. debug(' rule: time derivative (1.11, 1.12)')
  1549. d = []
  1550. for k in range(ma1[n]):
  1551. if k==0:
  1552. y = ma1[g].func(t).subs(t, 0)
  1553. else:
  1554. y = Derivative(ma1[g].func(t), (t, k)).subs(t, 0)
  1555. d.append(s**(ma1[n]-k-1)*y)
  1556. r = s**ma1[n]*_laplace_apply_rules(ma1[g].func(t), t, s, doit=doit,
  1557. **hints)
  1558. return r - Add(*d)
  1559. return None
  1560. def _laplace_apply_rules(f, t, s, doit=True, **hints):
  1561. """
  1562. Helper function for the class LaplaceTransform.
  1563. This function does a Laplace transform based on rules and, after
  1564. applying the rules, hands the rest over to `_laplace_transform`, which
  1565. will attempt to integrate.
  1566. If it is called with `doit=False`, then it will instead return
  1567. `LaplaceTransform` objects.
  1568. """
  1569. k, func = f.as_independent(t, as_Add=False)
  1570. simple_rules = _laplace_build_rules(t, s)
  1571. for t_dom, s_dom, check, plane, prep in simple_rules:
  1572. ma = prep(func).match(t_dom)
  1573. if ma:
  1574. debug('_laplace_apply_rules match:')
  1575. debug(' f: %s'%(func,))
  1576. debug(' rule: %s o---o %s'%(t_dom, s_dom))
  1577. try:
  1578. debug(' try %s'%(check,))
  1579. c = check.xreplace(ma)
  1580. debug(' check %s -> %s'%(check, c))
  1581. if c==True:
  1582. return _laplace_cr(k*s_dom.xreplace(ma),
  1583. plane.xreplace(ma), S.true, **hints)
  1584. except Exception:
  1585. debug('_laplace_apply_rules did not match.')
  1586. if f.has(DiracDelta):
  1587. return None
  1588. prog_rules = [_laplace_rule_timescale, _laplace_rule_heaviside,
  1589. _laplace_rule_exp, _laplace_rule_trig, _laplace_rule_diff]
  1590. for p_rule in prog_rules:
  1591. LT = p_rule(f, t, s, doit=doit, **hints)
  1592. if LT is not None:
  1593. return LT
  1594. return None
  1595. class LaplaceTransform(IntegralTransform):
  1596. """
  1597. Class representing unevaluated Laplace transforms.
  1598. For usage of this class, see the :class:`IntegralTransform` docstring.
  1599. For how to compute Laplace transforms, see the :func:`laplace_transform`
  1600. docstring.
  1601. """
  1602. _name = 'Laplace'
  1603. def _compute_transform(self, f, t, s, **hints):
  1604. LT = _laplace_apply_rules(f, t, s, **hints)
  1605. if LT is None:
  1606. _simplify = hints.pop('simplify', True)
  1607. debug('_laplace_apply_rules could not match function %s'%(f,))
  1608. debug(' hints: %s'%(hints,))
  1609. return _laplace_transform(f, t, s, simplify=_simplify, **hints)
  1610. else:
  1611. return LT
  1612. def _as_integral(self, f, t, s):
  1613. return Integral(f*exp(-s*t), (t, S.Zero, S.Infinity))
  1614. def _collapse_extra(self, extra):
  1615. conds = []
  1616. planes = []
  1617. for plane, cond in extra:
  1618. conds.append(cond)
  1619. planes.append(plane)
  1620. cond = And(*conds)
  1621. plane = Max(*planes)
  1622. if cond == False:
  1623. raise IntegralTransformError(
  1624. 'Laplace', None, 'No combined convergence.')
  1625. return plane, cond
  1626. def _try_directly(self, **hints):
  1627. fn = self.function
  1628. debug('----> _try_directly: %s'%(fn, ))
  1629. t_ = self.function_variable
  1630. s_ = self.transform_variable
  1631. LT = None
  1632. if not fn.is_Add:
  1633. fn = expand_mul(fn)
  1634. try:
  1635. LT = self._compute_transform(fn, t_, s_, **hints)
  1636. except IntegralTransformError:
  1637. LT = None
  1638. return fn, LT
  1639. def laplace_transform(f, t, s, legacy_matrix=True, **hints):
  1640. r"""
  1641. Compute the Laplace Transform `F(s)` of `f(t)`,
  1642. .. math :: F(s) = \int_{0^{-}}^\infty e^{-st} f(t) \mathrm{d}t.
  1643. Explanation
  1644. ===========
  1645. For all sensible functions, this converges absolutely in a
  1646. half-plane
  1647. .. math :: a < \operatorname{Re}(s)
  1648. This function returns ``(F, a, cond)`` where ``F`` is the Laplace
  1649. transform of ``f``, `a` is the half-plane of convergence, and `cond` are
  1650. auxiliary convergence conditions.
  1651. The implementation is rule-based, and if you are interested in which
  1652. rules are applied, and whether integration is attemped, you can switch
  1653. debug information on by setting ``sympy.SYMPY_DEBUG=True``.
  1654. The lower bound is `0-`, meaning that this bound should be approached
  1655. from the lower side. This is only necessary if distributions are involved.
  1656. At present, it is only done if `f(t)` contains ``DiracDelta``, in which
  1657. case the Laplace transform is computed implicitly as
  1658. .. math :: F(s) = \lim_{\tau\to 0^{-}} \int_{\tau}^\infty e^{-st} f(t) \mathrm{d}t
  1659. by applying rules.
  1660. If the integral cannot be fully computed in closed form, this function
  1661. returns an unevaluated :class:`LaplaceTransform` object.
  1662. For a description of possible hints, refer to the docstring of
  1663. :func:`sympy.integrals.transforms.IntegralTransform.doit`. If ``noconds=True``,
  1664. only `F` will be returned (i.e. not ``cond``, and also not the plane ``a``).
  1665. .. deprecated:: 1.9
  1666. Legacy behavior for matrices where ``laplace_transform`` with
  1667. ``noconds=False`` (the default) returns a Matrix whose elements are
  1668. tuples. The behavior of ``laplace_transform`` for matrices will change
  1669. in a future release of SymPy to return a tuple of the transformed
  1670. Matrix and the convergence conditions for the matrix as a whole. Use
  1671. ``legacy_matrix=False`` to enable the new behavior.
  1672. Examples
  1673. ========
  1674. >>> from sympy import DiracDelta, exp, laplace_transform
  1675. >>> from sympy.abc import t, s, a
  1676. >>> laplace_transform(t**4, t, s)
  1677. (24/s**5, 0, True)
  1678. >>> laplace_transform(t**a, t, s)
  1679. (gamma(a + 1)/(s*s**a), 0, re(a) > -1)
  1680. >>> laplace_transform(DiracDelta(t)-a*exp(-a*t),t,s)
  1681. (s/(a + s), Max(0, -a), True)
  1682. See Also
  1683. ========
  1684. inverse_laplace_transform, mellin_transform, fourier_transform
  1685. hankel_transform, inverse_hankel_transform
  1686. """
  1687. debug('\n***** laplace_transform(%s, %s, %s)'%(f, t, s))
  1688. if isinstance(f, MatrixBase) and hasattr(f, 'applyfunc'):
  1689. conds = not hints.get('noconds', False)
  1690. if conds and legacy_matrix:
  1691. sympy_deprecation_warning(
  1692. """
  1693. Calling laplace_transform() on a Matrix with noconds=False (the default) is
  1694. deprecated. Either noconds=True or use legacy_matrix=False to get the new
  1695. behavior.
  1696. """,
  1697. deprecated_since_version="1.9",
  1698. active_deprecations_target="deprecated-laplace-transform-matrix",
  1699. )
  1700. # Temporarily disable the deprecation warning for non-Expr objects
  1701. # in Matrix
  1702. with ignore_warnings(SymPyDeprecationWarning):
  1703. return f.applyfunc(lambda fij: laplace_transform(fij, t, s, **hints))
  1704. else:
  1705. elements_trans = [laplace_transform(fij, t, s, **hints) for fij in f]
  1706. if conds:
  1707. elements, avals, conditions = zip(*elements_trans)
  1708. f_laplace = type(f)(*f.shape, elements)
  1709. return f_laplace, Max(*avals), And(*conditions)
  1710. else:
  1711. return type(f)(*f.shape, elements_trans)
  1712. return LaplaceTransform(f, t, s).doit(**hints)
  1713. @_noconds_(True)
  1714. def _inverse_laplace_transform(F, s, t_, plane, simplify=True):
  1715. """ The backend function for inverse Laplace transforms. """
  1716. from sympy.integrals.meijerint import meijerint_inversion, _get_coeff_exp
  1717. # There are two strategies we can try:
  1718. # 1) Use inverse mellin transforms - related by a simple change of variables.
  1719. # 2) Use the inversion integral.
  1720. t = Dummy('t', real=True)
  1721. def pw_simp(*args):
  1722. """ Simplify a piecewise expression from hyperexpand. """
  1723. # XXX we break modularity here!
  1724. if len(args) != 3:
  1725. return Piecewise(*args)
  1726. arg = args[2].args[0].argument
  1727. coeff, exponent = _get_coeff_exp(arg, t)
  1728. e1 = args[0].args[0]
  1729. e2 = args[1].args[0]
  1730. return Heaviside(1/Abs(coeff) - t**exponent)*e1 \
  1731. + Heaviside(t**exponent - 1/Abs(coeff))*e2
  1732. if F.is_rational_function(s):
  1733. F = F.apart(s)
  1734. if F.is_Add:
  1735. f = Add(*[_inverse_laplace_transform(X, s, t, plane, simplify)\
  1736. for X in F.args])
  1737. return _simplify(f.subs(t, t_), simplify), True
  1738. try:
  1739. f, cond = inverse_mellin_transform(F, s, exp(-t), (None, S.Infinity),
  1740. needeval=True, noconds=False)
  1741. except IntegralTransformError:
  1742. f = None
  1743. if f is None:
  1744. f = meijerint_inversion(F, s, t)
  1745. if f is None:
  1746. raise IntegralTransformError('Inverse Laplace', f, '')
  1747. if f.is_Piecewise:
  1748. f, cond = f.args[0]
  1749. if f.has(Integral):
  1750. raise IntegralTransformError('Inverse Laplace', f,
  1751. 'inversion integral of unrecognised form.')
  1752. else:
  1753. cond = S.true
  1754. f = f.replace(Piecewise, pw_simp)
  1755. if f.is_Piecewise:
  1756. # many of the functions called below can't work with piecewise
  1757. # (b/c it has a bool in args)
  1758. return f.subs(t, t_), cond
  1759. u = Dummy('u')
  1760. def simp_heaviside(arg, H0=S.Half):
  1761. a = arg.subs(exp(-t), u)
  1762. if a.has(t):
  1763. return Heaviside(arg, H0)
  1764. rel = _solve_inequality(a > 0, u)
  1765. if rel.lts == u:
  1766. k = log(rel.gts)
  1767. return Heaviside(t + k, H0)
  1768. else:
  1769. k = log(rel.lts)
  1770. return Heaviside(-(t + k), H0)
  1771. f = f.replace(Heaviside, simp_heaviside)
  1772. def simp_exp(arg):
  1773. return expand_complex(exp(arg))
  1774. f = f.replace(exp, simp_exp)
  1775. # TODO it would be nice to fix cosh and sinh ... simplify messes these
  1776. # exponentials up
  1777. return _simplify(f.subs(t, t_), simplify), cond
  1778. class InverseLaplaceTransform(IntegralTransform):
  1779. """
  1780. Class representing unevaluated inverse Laplace transforms.
  1781. For usage of this class, see the :class:`IntegralTransform` docstring.
  1782. For how to compute inverse Laplace transforms, see the
  1783. :func:`inverse_laplace_transform` docstring.
  1784. """
  1785. _name = 'Inverse Laplace'
  1786. _none_sentinel = Dummy('None')
  1787. _c = Dummy('c')
  1788. def __new__(cls, F, s, x, plane, **opts):
  1789. if plane is None:
  1790. plane = InverseLaplaceTransform._none_sentinel
  1791. return IntegralTransform.__new__(cls, F, s, x, plane, **opts)
  1792. @property
  1793. def fundamental_plane(self):
  1794. plane = self.args[3]
  1795. if plane is InverseLaplaceTransform._none_sentinel:
  1796. plane = None
  1797. return plane
  1798. def _compute_transform(self, F, s, t, **hints):
  1799. return _inverse_laplace_transform(F, s, t, self.fundamental_plane, **hints)
  1800. def _as_integral(self, F, s, t):
  1801. c = self.__class__._c
  1802. return Integral(exp(s*t)*F, (s, c - S.ImaginaryUnit*S.Infinity,
  1803. c + S.ImaginaryUnit*S.Infinity))/(2*S.Pi*S.ImaginaryUnit)
  1804. def inverse_laplace_transform(F, s, t, plane=None, **hints):
  1805. r"""
  1806. Compute the inverse Laplace transform of `F(s)`, defined as
  1807. .. math :: f(t) = \frac{1}{2\pi i} \int_{c-i\infty}^{c+i\infty} e^{st} F(s) \mathrm{d}s,
  1808. for `c` so large that `F(s)` has no singularites in the
  1809. half-plane `\operatorname{Re}(s) > c-\epsilon`.
  1810. Explanation
  1811. ===========
  1812. The plane can be specified by
  1813. argument ``plane``, but will be inferred if passed as None.
  1814. Under certain regularity conditions, this recovers `f(t)` from its
  1815. Laplace Transform `F(s)`, for non-negative `t`, and vice
  1816. versa.
  1817. If the integral cannot be computed in closed form, this function returns
  1818. an unevaluated :class:`InverseLaplaceTransform` object.
  1819. Note that this function will always assume `t` to be real,
  1820. regardless of the SymPy assumption on `t`.
  1821. For a description of possible hints, refer to the docstring of
  1822. :func:`sympy.integrals.transforms.IntegralTransform.doit`.
  1823. Examples
  1824. ========
  1825. >>> from sympy import inverse_laplace_transform, exp, Symbol
  1826. >>> from sympy.abc import s, t
  1827. >>> a = Symbol('a', positive=True)
  1828. >>> inverse_laplace_transform(exp(-a*s)/s, s, t)
  1829. Heaviside(-a + t)
  1830. See Also
  1831. ========
  1832. laplace_transform, _fast_inverse_laplace
  1833. hankel_transform, inverse_hankel_transform
  1834. """
  1835. if isinstance(F, MatrixBase) and hasattr(F, 'applyfunc'):
  1836. return F.applyfunc(lambda Fij: inverse_laplace_transform(Fij, s, t, plane, **hints))
  1837. return InverseLaplaceTransform(F, s, t, plane).doit(**hints)
  1838. def _fast_inverse_laplace(e, s, t):
  1839. """Fast inverse Laplace transform of rational function including RootSum"""
  1840. a, b, n = symbols('a, b, n', cls=Wild, exclude=[s])
  1841. def _ilt(e):
  1842. if not e.has(s):
  1843. return e
  1844. elif e.is_Add:
  1845. return _ilt_add(e)
  1846. elif e.is_Mul:
  1847. return _ilt_mul(e)
  1848. elif e.is_Pow:
  1849. return _ilt_pow(e)
  1850. elif isinstance(e, RootSum):
  1851. return _ilt_rootsum(e)
  1852. else:
  1853. raise NotImplementedError
  1854. def _ilt_add(e):
  1855. return e.func(*map(_ilt, e.args))
  1856. def _ilt_mul(e):
  1857. coeff, expr = e.as_independent(s)
  1858. if expr.is_Mul:
  1859. raise NotImplementedError
  1860. return coeff * _ilt(expr)
  1861. def _ilt_pow(e):
  1862. match = e.match((a*s + b)**n)
  1863. if match is not None:
  1864. nm, am, bm = match[n], match[a], match[b]
  1865. if nm.is_Integer and nm < 0:
  1866. return t**(-nm-1)*exp(-(bm/am)*t)/(am**-nm*gamma(-nm))
  1867. if nm == 1:
  1868. return exp(-(bm/am)*t) / am
  1869. raise NotImplementedError
  1870. def _ilt_rootsum(e):
  1871. expr = e.fun.expr
  1872. [variable] = e.fun.variables
  1873. return RootSum(e.poly, Lambda(variable, together(_ilt(expr))))
  1874. return _ilt(e)
  1875. ##########################################################################
  1876. # Fourier Transform
  1877. ##########################################################################
  1878. @_noconds_(True)
  1879. def _fourier_transform(f, x, k, a, b, name, simplify=True):
  1880. r"""
  1881. Compute a general Fourier-type transform
  1882. .. math::
  1883. F(k) = a \int_{-\infty}^{\infty} e^{bixk} f(x)\, dx.
  1884. For suitable choice of *a* and *b*, this reduces to the standard Fourier
  1885. and inverse Fourier transforms.
  1886. """
  1887. F = integrate(a*f*exp(b*S.ImaginaryUnit*x*k), (x, S.NegativeInfinity, S.Infinity))
  1888. if not F.has(Integral):
  1889. return _simplify(F, simplify), S.true
  1890. integral_f = integrate(f, (x, S.NegativeInfinity, S.Infinity))
  1891. if integral_f in (S.NegativeInfinity, S.Infinity, S.NaN) or integral_f.has(Integral):
  1892. raise IntegralTransformError(name, f, 'function not integrable on real axis')
  1893. if not F.is_Piecewise:
  1894. raise IntegralTransformError(name, f, 'could not compute integral')
  1895. F, cond = F.args[0]
  1896. if F.has(Integral):
  1897. raise IntegralTransformError(name, f, 'integral in unexpected form')
  1898. return _simplify(F, simplify), cond
  1899. class FourierTypeTransform(IntegralTransform):
  1900. """ Base class for Fourier transforms."""
  1901. def a(self):
  1902. raise NotImplementedError(
  1903. "Class %s must implement a(self) but does not" % self.__class__)
  1904. def b(self):
  1905. raise NotImplementedError(
  1906. "Class %s must implement b(self) but does not" % self.__class__)
  1907. def _compute_transform(self, f, x, k, **hints):
  1908. return _fourier_transform(f, x, k,
  1909. self.a(), self.b(),
  1910. self.__class__._name, **hints)
  1911. def _as_integral(self, f, x, k):
  1912. a = self.a()
  1913. b = self.b()
  1914. return Integral(a*f*exp(b*S.ImaginaryUnit*x*k), (x, S.NegativeInfinity, S.Infinity))
  1915. class FourierTransform(FourierTypeTransform):
  1916. """
  1917. Class representing unevaluated Fourier transforms.
  1918. For usage of this class, see the :class:`IntegralTransform` docstring.
  1919. For how to compute Fourier transforms, see the :func:`fourier_transform`
  1920. docstring.
  1921. """
  1922. _name = 'Fourier'
  1923. def a(self):
  1924. return 1
  1925. def b(self):
  1926. return -2*S.Pi
  1927. def fourier_transform(f, x, k, **hints):
  1928. r"""
  1929. Compute the unitary, ordinary-frequency Fourier transform of ``f``, defined
  1930. as
  1931. .. math:: F(k) = \int_{-\infty}^\infty f(x) e^{-2\pi i x k} \mathrm{d} x.
  1932. Explanation
  1933. ===========
  1934. If the transform cannot be computed in closed form, this
  1935. function returns an unevaluated :class:`FourierTransform` object.
  1936. For other Fourier transform conventions, see the function
  1937. :func:`sympy.integrals.transforms._fourier_transform`.
  1938. For a description of possible hints, refer to the docstring of
  1939. :func:`sympy.integrals.transforms.IntegralTransform.doit`.
  1940. Note that for this transform, by default ``noconds=True``.
  1941. Examples
  1942. ========
  1943. >>> from sympy import fourier_transform, exp
  1944. >>> from sympy.abc import x, k
  1945. >>> fourier_transform(exp(-x**2), x, k)
  1946. sqrt(pi)*exp(-pi**2*k**2)
  1947. >>> fourier_transform(exp(-x**2), x, k, noconds=False)
  1948. (sqrt(pi)*exp(-pi**2*k**2), True)
  1949. See Also
  1950. ========
  1951. inverse_fourier_transform
  1952. sine_transform, inverse_sine_transform
  1953. cosine_transform, inverse_cosine_transform
  1954. hankel_transform, inverse_hankel_transform
  1955. mellin_transform, laplace_transform
  1956. """
  1957. return FourierTransform(f, x, k).doit(**hints)
  1958. class InverseFourierTransform(FourierTypeTransform):
  1959. """
  1960. Class representing unevaluated inverse Fourier transforms.
  1961. For usage of this class, see the :class:`IntegralTransform` docstring.
  1962. For how to compute inverse Fourier transforms, see the
  1963. :func:`inverse_fourier_transform` docstring.
  1964. """
  1965. _name = 'Inverse Fourier'
  1966. def a(self):
  1967. return 1
  1968. def b(self):
  1969. return 2*S.Pi
  1970. def inverse_fourier_transform(F, k, x, **hints):
  1971. r"""
  1972. Compute the unitary, ordinary-frequency inverse Fourier transform of `F`,
  1973. defined as
  1974. .. math:: f(x) = \int_{-\infty}^\infty F(k) e^{2\pi i x k} \mathrm{d} k.
  1975. Explanation
  1976. ===========
  1977. If the transform cannot be computed in closed form, this
  1978. function returns an unevaluated :class:`InverseFourierTransform` object.
  1979. For other Fourier transform conventions, see the function
  1980. :func:`sympy.integrals.transforms._fourier_transform`.
  1981. For a description of possible hints, refer to the docstring of
  1982. :func:`sympy.integrals.transforms.IntegralTransform.doit`.
  1983. Note that for this transform, by default ``noconds=True``.
  1984. Examples
  1985. ========
  1986. >>> from sympy import inverse_fourier_transform, exp, sqrt, pi
  1987. >>> from sympy.abc import x, k
  1988. >>> inverse_fourier_transform(sqrt(pi)*exp(-(pi*k)**2), k, x)
  1989. exp(-x**2)
  1990. >>> inverse_fourier_transform(sqrt(pi)*exp(-(pi*k)**2), k, x, noconds=False)
  1991. (exp(-x**2), True)
  1992. See Also
  1993. ========
  1994. fourier_transform
  1995. sine_transform, inverse_sine_transform
  1996. cosine_transform, inverse_cosine_transform
  1997. hankel_transform, inverse_hankel_transform
  1998. mellin_transform, laplace_transform
  1999. """
  2000. return InverseFourierTransform(F, k, x).doit(**hints)
  2001. ##########################################################################
  2002. # Fourier Sine and Cosine Transform
  2003. ##########################################################################
  2004. @_noconds_(True)
  2005. def _sine_cosine_transform(f, x, k, a, b, K, name, simplify=True):
  2006. """
  2007. Compute a general sine or cosine-type transform
  2008. F(k) = a int_0^oo b*sin(x*k) f(x) dx.
  2009. F(k) = a int_0^oo b*cos(x*k) f(x) dx.
  2010. For suitable choice of a and b, this reduces to the standard sine/cosine
  2011. and inverse sine/cosine transforms.
  2012. """
  2013. F = integrate(a*f*K(b*x*k), (x, S.Zero, S.Infinity))
  2014. if not F.has(Integral):
  2015. return _simplify(F, simplify), S.true
  2016. if not F.is_Piecewise:
  2017. raise IntegralTransformError(name, f, 'could not compute integral')
  2018. F, cond = F.args[0]
  2019. if F.has(Integral):
  2020. raise IntegralTransformError(name, f, 'integral in unexpected form')
  2021. return _simplify(F, simplify), cond
  2022. class SineCosineTypeTransform(IntegralTransform):
  2023. """
  2024. Base class for sine and cosine transforms.
  2025. Specify cls._kern.
  2026. """
  2027. def a(self):
  2028. raise NotImplementedError(
  2029. "Class %s must implement a(self) but does not" % self.__class__)
  2030. def b(self):
  2031. raise NotImplementedError(
  2032. "Class %s must implement b(self) but does not" % self.__class__)
  2033. def _compute_transform(self, f, x, k, **hints):
  2034. return _sine_cosine_transform(f, x, k,
  2035. self.a(), self.b(),
  2036. self.__class__._kern,
  2037. self.__class__._name, **hints)
  2038. def _as_integral(self, f, x, k):
  2039. a = self.a()
  2040. b = self.b()
  2041. K = self.__class__._kern
  2042. return Integral(a*f*K(b*x*k), (x, S.Zero, S.Infinity))
  2043. class SineTransform(SineCosineTypeTransform):
  2044. """
  2045. Class representing unevaluated sine transforms.
  2046. For usage of this class, see the :class:`IntegralTransform` docstring.
  2047. For how to compute sine transforms, see the :func:`sine_transform`
  2048. docstring.
  2049. """
  2050. _name = 'Sine'
  2051. _kern = sin
  2052. def a(self):
  2053. return sqrt(2)/sqrt(pi)
  2054. def b(self):
  2055. return S.One
  2056. def sine_transform(f, x, k, **hints):
  2057. r"""
  2058. Compute the unitary, ordinary-frequency sine transform of `f`, defined
  2059. as
  2060. .. math:: F(k) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty f(x) \sin(2\pi x k) \mathrm{d} x.
  2061. Explanation
  2062. ===========
  2063. If the transform cannot be computed in closed form, this
  2064. function returns an unevaluated :class:`SineTransform` object.
  2065. For a description of possible hints, refer to the docstring of
  2066. :func:`sympy.integrals.transforms.IntegralTransform.doit`.
  2067. Note that for this transform, by default ``noconds=True``.
  2068. Examples
  2069. ========
  2070. >>> from sympy import sine_transform, exp
  2071. >>> from sympy.abc import x, k, a
  2072. >>> sine_transform(x*exp(-a*x**2), x, k)
  2073. sqrt(2)*k*exp(-k**2/(4*a))/(4*a**(3/2))
  2074. >>> sine_transform(x**(-a), x, k)
  2075. 2**(1/2 - a)*k**(a - 1)*gamma(1 - a/2)/gamma(a/2 + 1/2)
  2076. See Also
  2077. ========
  2078. fourier_transform, inverse_fourier_transform
  2079. inverse_sine_transform
  2080. cosine_transform, inverse_cosine_transform
  2081. hankel_transform, inverse_hankel_transform
  2082. mellin_transform, laplace_transform
  2083. """
  2084. return SineTransform(f, x, k).doit(**hints)
  2085. class InverseSineTransform(SineCosineTypeTransform):
  2086. """
  2087. Class representing unevaluated inverse sine transforms.
  2088. For usage of this class, see the :class:`IntegralTransform` docstring.
  2089. For how to compute inverse sine transforms, see the
  2090. :func:`inverse_sine_transform` docstring.
  2091. """
  2092. _name = 'Inverse Sine'
  2093. _kern = sin
  2094. def a(self):
  2095. return sqrt(2)/sqrt(pi)
  2096. def b(self):
  2097. return S.One
  2098. def inverse_sine_transform(F, k, x, **hints):
  2099. r"""
  2100. Compute the unitary, ordinary-frequency inverse sine transform of `F`,
  2101. defined as
  2102. .. math:: f(x) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty F(k) \sin(2\pi x k) \mathrm{d} k.
  2103. Explanation
  2104. ===========
  2105. If the transform cannot be computed in closed form, this
  2106. function returns an unevaluated :class:`InverseSineTransform` object.
  2107. For a description of possible hints, refer to the docstring of
  2108. :func:`sympy.integrals.transforms.IntegralTransform.doit`.
  2109. Note that for this transform, by default ``noconds=True``.
  2110. Examples
  2111. ========
  2112. >>> from sympy import inverse_sine_transform, exp, sqrt, gamma
  2113. >>> from sympy.abc import x, k, a
  2114. >>> inverse_sine_transform(2**((1-2*a)/2)*k**(a - 1)*
  2115. ... gamma(-a/2 + 1)/gamma((a+1)/2), k, x)
  2116. x**(-a)
  2117. >>> inverse_sine_transform(sqrt(2)*k*exp(-k**2/(4*a))/(4*sqrt(a)**3), k, x)
  2118. x*exp(-a*x**2)
  2119. See Also
  2120. ========
  2121. fourier_transform, inverse_fourier_transform
  2122. sine_transform
  2123. cosine_transform, inverse_cosine_transform
  2124. hankel_transform, inverse_hankel_transform
  2125. mellin_transform, laplace_transform
  2126. """
  2127. return InverseSineTransform(F, k, x).doit(**hints)
  2128. class CosineTransform(SineCosineTypeTransform):
  2129. """
  2130. Class representing unevaluated cosine transforms.
  2131. For usage of this class, see the :class:`IntegralTransform` docstring.
  2132. For how to compute cosine transforms, see the :func:`cosine_transform`
  2133. docstring.
  2134. """
  2135. _name = 'Cosine'
  2136. _kern = cos
  2137. def a(self):
  2138. return sqrt(2)/sqrt(pi)
  2139. def b(self):
  2140. return S.One
  2141. def cosine_transform(f, x, k, **hints):
  2142. r"""
  2143. Compute the unitary, ordinary-frequency cosine transform of `f`, defined
  2144. as
  2145. .. math:: F(k) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty f(x) \cos(2\pi x k) \mathrm{d} x.
  2146. Explanation
  2147. ===========
  2148. If the transform cannot be computed in closed form, this
  2149. function returns an unevaluated :class:`CosineTransform` object.
  2150. For a description of possible hints, refer to the docstring of
  2151. :func:`sympy.integrals.transforms.IntegralTransform.doit`.
  2152. Note that for this transform, by default ``noconds=True``.
  2153. Examples
  2154. ========
  2155. >>> from sympy import cosine_transform, exp, sqrt, cos
  2156. >>> from sympy.abc import x, k, a
  2157. >>> cosine_transform(exp(-a*x), x, k)
  2158. sqrt(2)*a/(sqrt(pi)*(a**2 + k**2))
  2159. >>> cosine_transform(exp(-a*sqrt(x))*cos(a*sqrt(x)), x, k)
  2160. a*exp(-a**2/(2*k))/(2*k**(3/2))
  2161. See Also
  2162. ========
  2163. fourier_transform, inverse_fourier_transform,
  2164. sine_transform, inverse_sine_transform
  2165. inverse_cosine_transform
  2166. hankel_transform, inverse_hankel_transform
  2167. mellin_transform, laplace_transform
  2168. """
  2169. return CosineTransform(f, x, k).doit(**hints)
  2170. class InverseCosineTransform(SineCosineTypeTransform):
  2171. """
  2172. Class representing unevaluated inverse cosine transforms.
  2173. For usage of this class, see the :class:`IntegralTransform` docstring.
  2174. For how to compute inverse cosine transforms, see the
  2175. :func:`inverse_cosine_transform` docstring.
  2176. """
  2177. _name = 'Inverse Cosine'
  2178. _kern = cos
  2179. def a(self):
  2180. return sqrt(2)/sqrt(pi)
  2181. def b(self):
  2182. return S.One
  2183. def inverse_cosine_transform(F, k, x, **hints):
  2184. r"""
  2185. Compute the unitary, ordinary-frequency inverse cosine transform of `F`,
  2186. defined as
  2187. .. math:: f(x) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty F(k) \cos(2\pi x k) \mathrm{d} k.
  2188. Explanation
  2189. ===========
  2190. If the transform cannot be computed in closed form, this
  2191. function returns an unevaluated :class:`InverseCosineTransform` object.
  2192. For a description of possible hints, refer to the docstring of
  2193. :func:`sympy.integrals.transforms.IntegralTransform.doit`.
  2194. Note that for this transform, by default ``noconds=True``.
  2195. Examples
  2196. ========
  2197. >>> from sympy import inverse_cosine_transform, sqrt, pi
  2198. >>> from sympy.abc import x, k, a
  2199. >>> inverse_cosine_transform(sqrt(2)*a/(sqrt(pi)*(a**2 + k**2)), k, x)
  2200. exp(-a*x)
  2201. >>> inverse_cosine_transform(1/sqrt(k), k, x)
  2202. 1/sqrt(x)
  2203. See Also
  2204. ========
  2205. fourier_transform, inverse_fourier_transform,
  2206. sine_transform, inverse_sine_transform
  2207. cosine_transform
  2208. hankel_transform, inverse_hankel_transform
  2209. mellin_transform, laplace_transform
  2210. """
  2211. return InverseCosineTransform(F, k, x).doit(**hints)
  2212. ##########################################################################
  2213. # Hankel Transform
  2214. ##########################################################################
  2215. @_noconds_(True)
  2216. def _hankel_transform(f, r, k, nu, name, simplify=True):
  2217. r"""
  2218. Compute a general Hankel transform
  2219. .. math:: F_\nu(k) = \int_{0}^\infty f(r) J_\nu(k r) r \mathrm{d} r.
  2220. """
  2221. F = integrate(f*besselj(nu, k*r)*r, (r, S.Zero, S.Infinity))
  2222. if not F.has(Integral):
  2223. return _simplify(F, simplify), S.true
  2224. if not F.is_Piecewise:
  2225. raise IntegralTransformError(name, f, 'could not compute integral')
  2226. F, cond = F.args[0]
  2227. if F.has(Integral):
  2228. raise IntegralTransformError(name, f, 'integral in unexpected form')
  2229. return _simplify(F, simplify), cond
  2230. class HankelTypeTransform(IntegralTransform):
  2231. """
  2232. Base class for Hankel transforms.
  2233. """
  2234. def doit(self, **hints):
  2235. return self._compute_transform(self.function,
  2236. self.function_variable,
  2237. self.transform_variable,
  2238. self.args[3],
  2239. **hints)
  2240. def _compute_transform(self, f, r, k, nu, **hints):
  2241. return _hankel_transform(f, r, k, nu, self._name, **hints)
  2242. def _as_integral(self, f, r, k, nu):
  2243. return Integral(f*besselj(nu, k*r)*r, (r, S.Zero, S.Infinity))
  2244. @property
  2245. def as_integral(self):
  2246. return self._as_integral(self.function,
  2247. self.function_variable,
  2248. self.transform_variable,
  2249. self.args[3])
  2250. class HankelTransform(HankelTypeTransform):
  2251. """
  2252. Class representing unevaluated Hankel transforms.
  2253. For usage of this class, see the :class:`IntegralTransform` docstring.
  2254. For how to compute Hankel transforms, see the :func:`hankel_transform`
  2255. docstring.
  2256. """
  2257. _name = 'Hankel'
  2258. def hankel_transform(f, r, k, nu, **hints):
  2259. r"""
  2260. Compute the Hankel transform of `f`, defined as
  2261. .. math:: F_\nu(k) = \int_{0}^\infty f(r) J_\nu(k r) r \mathrm{d} r.
  2262. Explanation
  2263. ===========
  2264. If the transform cannot be computed in closed form, this
  2265. function returns an unevaluated :class:`HankelTransform` object.
  2266. For a description of possible hints, refer to the docstring of
  2267. :func:`sympy.integrals.transforms.IntegralTransform.doit`.
  2268. Note that for this transform, by default ``noconds=True``.
  2269. Examples
  2270. ========
  2271. >>> from sympy import hankel_transform, inverse_hankel_transform
  2272. >>> from sympy import exp
  2273. >>> from sympy.abc import r, k, m, nu, a
  2274. >>> ht = hankel_transform(1/r**m, r, k, nu)
  2275. >>> ht
  2276. 2*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/(2**m*gamma(m/2 + nu/2))
  2277. >>> inverse_hankel_transform(ht, k, r, nu)
  2278. r**(-m)
  2279. >>> ht = hankel_transform(exp(-a*r), r, k, 0)
  2280. >>> ht
  2281. a/(k**3*(a**2/k**2 + 1)**(3/2))
  2282. >>> inverse_hankel_transform(ht, k, r, 0)
  2283. exp(-a*r)
  2284. See Also
  2285. ========
  2286. fourier_transform, inverse_fourier_transform
  2287. sine_transform, inverse_sine_transform
  2288. cosine_transform, inverse_cosine_transform
  2289. inverse_hankel_transform
  2290. mellin_transform, laplace_transform
  2291. """
  2292. return HankelTransform(f, r, k, nu).doit(**hints)
  2293. class InverseHankelTransform(HankelTypeTransform):
  2294. """
  2295. Class representing unevaluated inverse Hankel transforms.
  2296. For usage of this class, see the :class:`IntegralTransform` docstring.
  2297. For how to compute inverse Hankel transforms, see the
  2298. :func:`inverse_hankel_transform` docstring.
  2299. """
  2300. _name = 'Inverse Hankel'
  2301. def inverse_hankel_transform(F, k, r, nu, **hints):
  2302. r"""
  2303. Compute the inverse Hankel transform of `F` defined as
  2304. .. math:: f(r) = \int_{0}^\infty F_\nu(k) J_\nu(k r) k \mathrm{d} k.
  2305. Explanation
  2306. ===========
  2307. If the transform cannot be computed in closed form, this
  2308. function returns an unevaluated :class:`InverseHankelTransform` object.
  2309. For a description of possible hints, refer to the docstring of
  2310. :func:`sympy.integrals.transforms.IntegralTransform.doit`.
  2311. Note that for this transform, by default ``noconds=True``.
  2312. Examples
  2313. ========
  2314. >>> from sympy import hankel_transform, inverse_hankel_transform
  2315. >>> from sympy import exp
  2316. >>> from sympy.abc import r, k, m, nu, a
  2317. >>> ht = hankel_transform(1/r**m, r, k, nu)
  2318. >>> ht
  2319. 2*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/(2**m*gamma(m/2 + nu/2))
  2320. >>> inverse_hankel_transform(ht, k, r, nu)
  2321. r**(-m)
  2322. >>> ht = hankel_transform(exp(-a*r), r, k, 0)
  2323. >>> ht
  2324. a/(k**3*(a**2/k**2 + 1)**(3/2))
  2325. >>> inverse_hankel_transform(ht, k, r, 0)
  2326. exp(-a*r)
  2327. See Also
  2328. ========
  2329. fourier_transform, inverse_fourier_transform
  2330. sine_transform, inverse_sine_transform
  2331. cosine_transform, inverse_cosine_transform
  2332. hankel_transform
  2333. mellin_transform, laplace_transform
  2334. """
  2335. return InverseHankelTransform(F, k, r, nu).doit(**hints)