laplace.py 85 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377
  1. """Laplace Transforms"""
  2. import sys
  3. import sympy
  4. from sympy.core import S, pi, I
  5. from sympy.core.add import Add
  6. from sympy.core.cache import cacheit
  7. from sympy.core.expr import Expr
  8. from sympy.core.function import (
  9. AppliedUndef, Derivative, expand, expand_complex, expand_mul, expand_trig,
  10. Lambda, WildFunction, diff, Subs)
  11. from sympy.core.mul import Mul, prod
  12. from sympy.core.relational import (
  13. _canonical, Ge, Gt, Lt, Unequality, Eq, Ne, Relational)
  14. from sympy.core.sorting import ordered
  15. from sympy.core.symbol import Dummy, symbols, Wild
  16. from sympy.functions.elementary.complexes import (
  17. re, im, arg, Abs, polar_lift, periodic_argument)
  18. from sympy.functions.elementary.exponential import exp, log
  19. from sympy.functions.elementary.hyperbolic import cosh, coth, sinh, asinh
  20. from sympy.functions.elementary.miscellaneous import Max, Min, sqrt
  21. from sympy.functions.elementary.piecewise import (
  22. Piecewise, piecewise_exclusive)
  23. from sympy.functions.elementary.trigonometric import cos, sin, atan, sinc
  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 (
  28. digamma, gamma, lowergamma, uppergamma)
  29. from sympy.functions.special.singularity_functions import SingularityFunction
  30. from sympy.integrals import integrate, Integral
  31. from sympy.integrals.transforms import (
  32. _simplify, IntegralTransform, IntegralTransformError)
  33. from sympy.logic.boolalg import to_cnf, conjuncts, disjuncts, Or, And
  34. from sympy.matrices.matrixbase import MatrixBase
  35. from sympy.polys.matrices.linsolve import _lin_eq2dict
  36. from sympy.polys.polyerrors import PolynomialError
  37. from sympy.polys.polyroots import roots
  38. from sympy.polys.polytools import Poly
  39. from sympy.polys.rationaltools import together
  40. from sympy.polys.rootoftools import RootSum
  41. from sympy.utilities.exceptions import (
  42. sympy_deprecation_warning, SymPyDeprecationWarning, ignore_warnings)
  43. from sympy.utilities.misc import debugf
  44. _LT_level = 0
  45. def DEBUG_WRAP(func):
  46. def wrap(*args, **kwargs):
  47. from sympy import SYMPY_DEBUG
  48. global _LT_level
  49. if not SYMPY_DEBUG:
  50. return func(*args, **kwargs)
  51. if _LT_level == 0:
  52. print('\n' + '-'*78, file=sys.stderr)
  53. print('-LT- %s%s%s' % (' '*_LT_level, func.__name__, args),
  54. file=sys.stderr)
  55. _LT_level += 1
  56. if (
  57. func.__name__ == '_laplace_transform_integration' or
  58. func.__name__ == '_inverse_laplace_transform_integration'):
  59. sympy.SYMPY_DEBUG = False
  60. print('**** %sIntegrating ...' % (' '*_LT_level), file=sys.stderr)
  61. result = func(*args, **kwargs)
  62. sympy.SYMPY_DEBUG = True
  63. else:
  64. result = func(*args, **kwargs)
  65. _LT_level -= 1
  66. print('-LT- %s---> %s' % (' '*_LT_level, result), file=sys.stderr)
  67. if _LT_level == 0:
  68. print('-'*78 + '\n', file=sys.stderr)
  69. return result
  70. return wrap
  71. def _debug(text):
  72. from sympy import SYMPY_DEBUG
  73. if SYMPY_DEBUG:
  74. print('-LT- %s%s' % (' '*_LT_level, text), file=sys.stderr)
  75. def _simplifyconds(expr, s, a):
  76. r"""
  77. Naively simplify some conditions occurring in ``expr``,
  78. given that `\operatorname{Re}(s) > a`.
  79. Examples
  80. ========
  81. >>> from sympy.integrals.laplace import _simplifyconds
  82. >>> from sympy.abc import x
  83. >>> from sympy import sympify as S
  84. >>> _simplifyconds(abs(x**2) < 1, x, 1)
  85. False
  86. >>> _simplifyconds(abs(x**2) < 1, x, 2)
  87. False
  88. >>> _simplifyconds(abs(x**2) < 1, x, 0)
  89. Abs(x**2) < 1
  90. >>> _simplifyconds(abs(1/x**2) < 1, x, 1)
  91. True
  92. >>> _simplifyconds(S(1) < abs(x), x, 1)
  93. True
  94. >>> _simplifyconds(S(1) < abs(1/x), x, 1)
  95. False
  96. >>> from sympy import Ne
  97. >>> _simplifyconds(Ne(1, x**3), x, 1)
  98. True
  99. >>> _simplifyconds(Ne(1, x**3), x, 2)
  100. True
  101. >>> _simplifyconds(Ne(1, x**3), x, 0)
  102. Ne(1, x**3)
  103. """
  104. def power(ex):
  105. if ex == s:
  106. return 1
  107. if ex.is_Pow and ex.base == s:
  108. return ex.exp
  109. return None
  110. def bigger(ex1, ex2):
  111. """ Return True only if |ex1| > |ex2|, False only if |ex1| < |ex2|.
  112. Else return None. """
  113. if ex1.has(s) and ex2.has(s):
  114. return None
  115. if isinstance(ex1, Abs):
  116. ex1 = ex1.args[0]
  117. if isinstance(ex2, Abs):
  118. ex2 = ex2.args[0]
  119. if ex1.has(s):
  120. return bigger(1/ex2, 1/ex1)
  121. n = power(ex2)
  122. if n is None:
  123. return None
  124. try:
  125. if n > 0 and (Abs(ex1) <= Abs(a)**n) == S.true:
  126. return False
  127. if n < 0 and (Abs(ex1) >= Abs(a)**n) == S.true:
  128. return True
  129. except TypeError:
  130. return None
  131. def replie(x, y):
  132. """ simplify x < y """
  133. if (not (x.is_positive or isinstance(x, Abs))
  134. or not (y.is_positive or isinstance(y, Abs))):
  135. return (x < y)
  136. r = bigger(x, y)
  137. if r is not None:
  138. return not r
  139. return (x < y)
  140. def replue(x, y):
  141. b = bigger(x, y)
  142. if b in (True, False):
  143. return True
  144. return Unequality(x, y)
  145. def repl(ex, *args):
  146. if ex in (True, False):
  147. return bool(ex)
  148. return ex.replace(*args)
  149. from sympy.simplify.radsimp import collect_abs
  150. expr = collect_abs(expr)
  151. expr = repl(expr, Lt, replie)
  152. expr = repl(expr, Gt, lambda x, y: replie(y, x))
  153. expr = repl(expr, Unequality, replue)
  154. return S(expr)
  155. @DEBUG_WRAP
  156. def expand_dirac_delta(expr):
  157. """
  158. Expand an expression involving DiractDelta to get it as a linear
  159. combination of DiracDelta functions.
  160. """
  161. return _lin_eq2dict(expr, expr.atoms(DiracDelta))
  162. @DEBUG_WRAP
  163. def _laplace_transform_integration(f, t, s_, *, simplify):
  164. """ The backend function for doing Laplace transforms by integration.
  165. This backend assumes that the frontend has already split sums
  166. such that `f` is to an addition anymore.
  167. """
  168. s = Dummy('s')
  169. if f.has(DiracDelta):
  170. return None
  171. F = integrate(f*exp(-s*t), (t, S.Zero, S.Infinity))
  172. if not F.has(Integral):
  173. return _simplify(F.subs(s, s_), simplify), S.NegativeInfinity, S.true
  174. if not F.is_Piecewise:
  175. return None
  176. F, cond = F.args[0]
  177. if F.has(Integral):
  178. return None
  179. def process_conds(conds):
  180. """ Turn ``conds`` into a strip and auxiliary conditions. """
  181. from sympy.solvers.inequalities import _solve_inequality
  182. a = S.NegativeInfinity
  183. aux = S.true
  184. conds = conjuncts(to_cnf(conds))
  185. p, q, w1, w2, w3, w4, w5 = symbols(
  186. 'p q w1 w2 w3 w4 w5', cls=Wild, exclude=[s])
  187. patterns = (
  188. p*Abs(arg((s + w3)*q)) < w2,
  189. p*Abs(arg((s + w3)*q)) <= w2,
  190. Abs(periodic_argument((s + w3)**p*q, w1)) < w2,
  191. Abs(periodic_argument((s + w3)**p*q, w1)) <= w2,
  192. Abs(periodic_argument((polar_lift(s + w3))**p*q, w1)) < w2,
  193. Abs(periodic_argument((polar_lift(s + w3))**p*q, w1)) <= w2)
  194. for c in conds:
  195. a_ = S.Infinity
  196. aux_ = []
  197. for d in disjuncts(c):
  198. if d.is_Relational and s in d.rhs.free_symbols:
  199. d = d.reversed
  200. if d.is_Relational and isinstance(d, (Ge, Gt)):
  201. d = d.reversedsign
  202. for pat in patterns:
  203. m = d.match(pat)
  204. if m:
  205. break
  206. if m and m[q].is_positive and m[w2]/m[p] == pi/2:
  207. d = -re(s + m[w3]) < 0
  208. m = d.match(p - cos(w1*Abs(arg(s*w5))*w2)*Abs(s**w3)**w4 < 0)
  209. if not m:
  210. m = d.match(
  211. cos(p - Abs(periodic_argument(s**w1*w5, q))*w2) *
  212. Abs(s**w3)**w4 < 0)
  213. if not m:
  214. m = d.match(
  215. p - cos(
  216. Abs(periodic_argument(polar_lift(s)**w1*w5, q))*w2
  217. )*Abs(s**w3)**w4 < 0)
  218. if m and all(m[wild].is_positive for wild in [
  219. w1, w2, w3, w4, w5]):
  220. d = re(s) > m[p]
  221. d_ = d.replace(
  222. re, lambda x: x.expand().as_real_imag()[0]).subs(re(s), t)
  223. if (
  224. not d.is_Relational or d.rel_op in ('==', '!=')
  225. or d_.has(s) or not d_.has(t)):
  226. aux_ += [d]
  227. continue
  228. soln = _solve_inequality(d_, t)
  229. if not soln.is_Relational or soln.rel_op in ('==', '!='):
  230. aux_ += [d]
  231. continue
  232. if soln.lts == t:
  233. return None
  234. else:
  235. a_ = Min(soln.lts, a_)
  236. if a_ is not S.Infinity:
  237. a = Max(a_, a)
  238. else:
  239. aux = And(aux, Or(*aux_))
  240. return a, aux.canonical if aux.is_Relational else aux
  241. conds = [process_conds(c) for c in disjuncts(cond)]
  242. conds2 = [x for x in conds if x[1] !=
  243. S.false and x[0] is not S.NegativeInfinity]
  244. if not conds2:
  245. conds2 = [x for x in conds if x[1] != S.false]
  246. conds = list(ordered(conds2))
  247. def cnt(expr):
  248. if expr in (True, False):
  249. return 0
  250. return expr.count_ops()
  251. conds.sort(key=lambda x: (-x[0], cnt(x[1])))
  252. if not conds:
  253. return None
  254. a, aux = conds[0] # XXX is [0] always the right one?
  255. def sbs(expr):
  256. return expr.subs(s, s_)
  257. if simplify:
  258. F = _simplifyconds(F, s, a)
  259. aux = _simplifyconds(aux, s, a)
  260. return _simplify(F.subs(s, s_), simplify), sbs(a), _canonical(sbs(aux))
  261. @DEBUG_WRAP
  262. def _laplace_deep_collect(f, t):
  263. """
  264. This is an internal helper function that traverses through the expression
  265. tree of `f(t)` and collects arguments. The purpose of it is that
  266. anything like `f(w*t-1*t-c)` will be written as `f((w-1)*t-c)` such that
  267. it can match `f(a*t+b)`.
  268. """
  269. if not isinstance(f, Expr):
  270. return f
  271. if (p := f.as_poly(t)) is not None:
  272. return p.as_expr()
  273. func = f.func
  274. args = [_laplace_deep_collect(arg, t) for arg in f.args]
  275. return func(*args)
  276. @cacheit
  277. def _laplace_build_rules():
  278. """
  279. This is an internal helper function that returns the table of Laplace
  280. transform rules in terms of the time variable `t` and the frequency
  281. variable `s`. It is used by ``_laplace_apply_rules``. Each entry is a
  282. tuple containing:
  283. (time domain pattern,
  284. frequency-domain replacement,
  285. condition for the rule to be applied,
  286. convergence plane,
  287. preparation function)
  288. The preparation function is a function with one argument that is applied
  289. to the expression before matching. For most rules it should be
  290. ``_laplace_deep_collect``.
  291. """
  292. t = Dummy('t')
  293. s = Dummy('s')
  294. a = Wild('a', exclude=[t])
  295. b = Wild('b', exclude=[t])
  296. n = Wild('n', exclude=[t])
  297. tau = Wild('tau', exclude=[t])
  298. omega = Wild('omega', exclude=[t])
  299. def dco(f): return _laplace_deep_collect(f, t)
  300. _debug('_laplace_build_rules is building rules')
  301. laplace_transform_rules = [
  302. (a, a/s,
  303. S.true, S.Zero, dco), # 4.2.1
  304. (DiracDelta(a*t-b), exp(-s*b/a)/Abs(a),
  305. Or(And(a > 0, b >= 0), And(a < 0, b <= 0)),
  306. S.NegativeInfinity, dco), # Not in Bateman54
  307. (DiracDelta(a*t-b), S(0),
  308. Or(And(a < 0, b >= 0), And(a > 0, b <= 0)),
  309. S.NegativeInfinity, dco), # Not in Bateman54
  310. (Heaviside(a*t-b), exp(-s*b/a)/s,
  311. And(a > 0, b > 0), S.Zero, dco), # 4.4.1
  312. (Heaviside(a*t-b), (1-exp(-s*b/a))/s,
  313. And(a < 0, b < 0), S.Zero, dco), # 4.4.1
  314. (Heaviside(a*t-b), 1/s,
  315. And(a > 0, b <= 0), S.Zero, dco), # 4.4.1
  316. (Heaviside(a*t-b), 0,
  317. And(a < 0, b > 0), S.Zero, dco), # 4.4.1
  318. (t, 1/s**2,
  319. S.true, S.Zero, dco), # 4.2.3
  320. (1/(a*t+b), -exp(-b/a*s)*Ei(-b/a*s)/a,
  321. Abs(arg(b/a)) < pi, S.Zero, dco), # 4.2.6
  322. (1/sqrt(a*t+b), sqrt(a*pi/s)*exp(b/a*s)*erfc(sqrt(b/a*s))/a,
  323. Abs(arg(b/a)) < pi, S.Zero, dco), # 4.2.18
  324. ((a*t+b)**(-S(3)/2),
  325. 2*b**(-S(1)/2)-2*(pi*s/a)**(S(1)/2)*exp(b/a*s) * erfc(sqrt(b/a*s))/a,
  326. Abs(arg(b/a)) < pi, S.Zero, dco), # 4.2.20
  327. (sqrt(t)/(t+b), sqrt(pi/s)-pi*sqrt(b)*exp(b*s)*erfc(sqrt(b*s)),
  328. Abs(arg(b)) < pi, S.Zero, dco), # 4.2.22
  329. (1/(a*sqrt(t) + t**(3/2)), pi*a**(S(1)/2)*exp(a*s)*erfc(sqrt(a*s)),
  330. S.true, S.Zero, dco), # Not in Bateman54
  331. (t**n, gamma(n+1)/s**(n+1),
  332. n > -1, S.Zero, dco), # 4.3.1
  333. ((a*t+b)**n, uppergamma(n+1, b/a*s)*exp(-b/a*s)/s**(n+1)/a,
  334. And(n > -1, Abs(arg(b/a)) < pi), S.Zero, dco), # 4.3.4
  335. (t**n/(t+a), a**n*gamma(n+1)*uppergamma(-n, a*s),
  336. And(n > -1, Abs(arg(a)) < pi), S.Zero, dco), # 4.3.7
  337. (exp(a*t-tau), exp(-tau)/(s-a),
  338. S.true, re(a), dco), # 4.5.1
  339. (t*exp(a*t-tau), exp(-tau)/(s-a)**2,
  340. S.true, re(a), dco), # 4.5.2
  341. (t**n*exp(a*t), gamma(n+1)/(s-a)**(n+1),
  342. re(n) > -1, re(a), dco), # 4.5.3
  343. (exp(-a*t**2), sqrt(pi/4/a)*exp(s**2/4/a)*erfc(s/sqrt(4*a)),
  344. re(a) > 0, S.Zero, dco), # 4.5.21
  345. (t*exp(-a*t**2),
  346. 1/(2*a)-2/sqrt(pi)/(4*a)**(S(3)/2)*s*erfc(s/sqrt(4*a)),
  347. re(a) > 0, S.Zero, dco), # 4.5.22
  348. (exp(-a/t), 2*sqrt(a/s)*besselk(1, 2*sqrt(a*s)),
  349. re(a) >= 0, S.Zero, dco), # 4.5.25
  350. (sqrt(t)*exp(-a/t),
  351. S(1)/2*sqrt(pi/s**3)*(1+2*sqrt(a*s))*exp(-2*sqrt(a*s)),
  352. re(a) >= 0, S.Zero, dco), # 4.5.26
  353. (exp(-a/t)/sqrt(t), sqrt(pi/s)*exp(-2*sqrt(a*s)),
  354. re(a) >= 0, S.Zero, dco), # 4.5.27
  355. (exp(-a/t)/(t*sqrt(t)), sqrt(pi/a)*exp(-2*sqrt(a*s)),
  356. re(a) > 0, S.Zero, dco), # 4.5.28
  357. (t**n*exp(-a/t), 2*(a/s)**((n+1)/2)*besselk(n+1, 2*sqrt(a*s)),
  358. re(a) > 0, S.Zero, dco), # 4.5.29
  359. # TODO: rules with sqrt(a*t) and sqrt(a/t) have stopped working after
  360. # changes to as_base_exp
  361. # (exp(-2*sqrt(a*t)),
  362. # s**(-1)-sqrt(pi*a)*s**(-S(3)/2)*exp(a/s) * erfc(sqrt(a/s)),
  363. # Abs(arg(a)) < pi, S.Zero, dco), # 4.5.31
  364. # (exp(-2*sqrt(a*t))/sqrt(t), (pi/s)**(S(1)/2)*exp(a/s)*erfc(sqrt(a/s)),
  365. # Abs(arg(a)) < pi, S.Zero, dco), # 4.5.33
  366. (exp(-a*exp(-t)), a**(-s)*lowergamma(s, a),
  367. S.true, S.Zero, dco), # 4.5.36
  368. (exp(-a*exp(t)), a**s*uppergamma(-s, a),
  369. re(a) > 0, S.Zero, dco), # 4.5.37
  370. (log(a*t), -log(exp(S.EulerGamma)*s/a)/s,
  371. a > 0, S.Zero, dco), # 4.6.1
  372. (log(1+a*t), -exp(s/a)/s*Ei(-s/a),
  373. Abs(arg(a)) < pi, S.Zero, dco), # 4.6.4
  374. (log(a*t+b), (log(b)-exp(s/b/a)/s*a*Ei(-s/b))/s*a,
  375. And(a > 0, Abs(arg(b)) < pi), S.Zero, dco), # 4.6.5
  376. (log(t)/sqrt(t), -sqrt(pi/s)*log(4*s*exp(S.EulerGamma)),
  377. S.true, S.Zero, dco), # 4.6.9
  378. (t**n*log(t), gamma(n+1)*s**(-n-1)*(digamma(n+1)-log(s)),
  379. re(n) > -1, S.Zero, dco), # 4.6.11
  380. (log(a*t)**2, (log(exp(S.EulerGamma)*s/a)**2+pi**2/6)/s,
  381. a > 0, S.Zero, dco), # 4.6.13
  382. (sin(omega*t), omega/(s**2+omega**2),
  383. S.true, Abs(im(omega)), dco), # 4,7,1
  384. (Abs(sin(omega*t)), omega/(s**2+omega**2)*coth(pi*s/2/omega),
  385. omega > 0, S.Zero, dco), # 4.7.2
  386. (sin(omega*t)/t, atan(omega/s),
  387. S.true, Abs(im(omega)), dco), # 4.7.16
  388. (sin(omega*t)**2/t, log(1+4*omega**2/s**2)/4,
  389. S.true, 2*Abs(im(omega)), dco), # 4.7.17
  390. (sin(omega*t)**2/t**2,
  391. omega*atan(2*omega/s)-s*log(1+4*omega**2/s**2)/4,
  392. S.true, 2*Abs(im(omega)), dco), # 4.7.20
  393. # (sin(2*sqrt(a*t)), sqrt(pi*a)/s/sqrt(s)*exp(-a/s),
  394. # S.true, S.Zero, dco), # 4.7.32
  395. # (sin(2*sqrt(a*t))/t, pi*erf(sqrt(a/s)),
  396. # S.true, S.Zero, dco), # 4.7.34
  397. (cos(omega*t), s/(s**2+omega**2),
  398. S.true, Abs(im(omega)), dco), # 4.7.43
  399. (cos(omega*t)**2, (s**2+2*omega**2)/(s**2+4*omega**2)/s,
  400. S.true, 2*Abs(im(omega)), dco), # 4.7.45
  401. # (sqrt(t)*cos(2*sqrt(a*t)), sqrt(pi)/2*s**(-S(5)/2)*(s-2*a)*exp(-a/s),
  402. # S.true, S.Zero, dco), # 4.7.66
  403. # (cos(2*sqrt(a*t))/sqrt(t), sqrt(pi/s)*exp(-a/s),
  404. # S.true, S.Zero, dco), # 4.7.67
  405. (sin(a*t)*sin(b*t), 2*a*b*s/(s**2+(a+b)**2)/(s**2+(a-b)**2),
  406. S.true, Abs(im(a))+Abs(im(b)), dco), # 4.7.78
  407. (cos(a*t)*sin(b*t), b*(s**2-a**2+b**2)/(s**2+(a+b)**2)/(s**2+(a-b)**2),
  408. S.true, Abs(im(a))+Abs(im(b)), dco), # 4.7.79
  409. (cos(a*t)*cos(b*t), s*(s**2+a**2+b**2)/(s**2+(a+b)**2)/(s**2+(a-b)**2),
  410. S.true, Abs(im(a))+Abs(im(b)), dco), # 4.7.80
  411. (sinh(a*t), a/(s**2-a**2),
  412. S.true, Abs(re(a)), dco), # 4.9.1
  413. (cosh(a*t), s/(s**2-a**2),
  414. S.true, Abs(re(a)), dco), # 4.9.2
  415. (sinh(a*t)**2, 2*a**2/(s**3-4*a**2*s),
  416. S.true, 2*Abs(re(a)), dco), # 4.9.3
  417. (cosh(a*t)**2, (s**2-2*a**2)/(s**3-4*a**2*s),
  418. S.true, 2*Abs(re(a)), dco), # 4.9.4
  419. (sinh(a*t)/t, log((s+a)/(s-a))/2,
  420. S.true, Abs(re(a)), dco), # 4.9.12
  421. (t**n*sinh(a*t), gamma(n+1)/2*((s-a)**(-n-1)-(s+a)**(-n-1)),
  422. n > -2, Abs(a), dco), # 4.9.18
  423. (t**n*cosh(a*t), gamma(n+1)/2*((s-a)**(-n-1)+(s+a)**(-n-1)),
  424. n > -1, Abs(a), dco), # 4.9.19
  425. # TODO
  426. # (sinh(2*sqrt(a*t)), sqrt(pi*a)/s/sqrt(s)*exp(a/s),
  427. # S.true, S.Zero, dco), # 4.9.34
  428. # (cosh(2*sqrt(a*t)), 1/s+sqrt(pi*a)/s/sqrt(s)*exp(a/s)*erf(sqrt(a/s)),
  429. # S.true, S.Zero, dco), # 4.9.35
  430. # (
  431. # sqrt(t)*sinh(2*sqrt(a*t)),
  432. # pi**(S(1)/2)*s**(-S(5)/2)*(s/2+a) *
  433. # exp(a/s)*erf(sqrt(a/s))-a**(S(1)/2)*s**(-2),
  434. # S.true, S.Zero, dco), # 4.9.36
  435. # (sqrt(t)*cosh(2*sqrt(a*t)), pi**(S(1)/2)*s**(-S(5)/2)*(s/2+a)*exp(a/s),
  436. # S.true, S.Zero, dco), # 4.9.37
  437. # (sinh(2*sqrt(a*t))/sqrt(t),
  438. # pi**(S(1)/2)*s**(-S(1)/2)*exp(a/s) * erf(sqrt(a/s)),
  439. # S.true, S.Zero, dco), # 4.9.38
  440. # (cosh(2*sqrt(a*t))/sqrt(t), pi**(S(1)/2)*s**(-S(1)/2)*exp(a/s),
  441. # S.true, S.Zero, dco), # 4.9.39
  442. # (sinh(sqrt(a*t))**2/sqrt(t), pi**(S(1)/2)/2*s**(-S(1)/2)*(exp(a/s)-1),
  443. # S.true, S.Zero, dco), # 4.9.40
  444. # (cosh(sqrt(a*t))**2/sqrt(t), pi**(S(1)/2)/2*s**(-S(1)/2)*(exp(a/s)+1),
  445. # S.true, S.Zero, dco), # 4.9.41
  446. (erf(a*t), exp(s**2/(2*a)**2)*erfc(s/(2*a))/s,
  447. 4*Abs(arg(a)) < pi, S.Zero, dco), # 4.12.2
  448. # (erf(sqrt(a*t)), sqrt(a)/sqrt(s+a)/s,
  449. # S.true, Max(S.Zero, -re(a)), dco), # 4.12.4
  450. # (exp(a*t)*erf(sqrt(a*t)), sqrt(a)/sqrt(s)/(s-a),
  451. # S.true, Max(S.Zero, re(a)), dco), # 4.12.5
  452. # (erf(sqrt(a/t)/2), (1-exp(-sqrt(a*s)))/s,
  453. # re(a) > 0, S.Zero, dco), # 4.12.6
  454. # (erfc(sqrt(a*t)), (sqrt(s+a)-sqrt(a))/sqrt(s+a)/s,
  455. # S.true, -re(a), dco), # 4.12.9
  456. # (exp(a*t)*erfc(sqrt(a*t)), 1/(s+sqrt(a*s)),
  457. # S.true, S.Zero, dco), # 4.12.10
  458. # (erfc(sqrt(a/t)/2), exp(-sqrt(a*s))/s,
  459. # re(a) > 0, S.Zero, dco), # 4.2.11
  460. (besselj(n, a*t), a**n/(sqrt(s**2+a**2)*(s+sqrt(s**2+a**2))**n),
  461. re(n) > -1, Abs(im(a)), dco), # 4.14.1
  462. (t**b*besselj(n, a*t),
  463. 2**n/sqrt(pi)*gamma(n+S.Half)*a**n*(s**2+a**2)**(-n-S.Half),
  464. And(re(n) > -S.Half, Eq(b, n)), Abs(im(a)), dco), # 4.14.7
  465. (t**b*besselj(n, a*t),
  466. 2**(n+1)/sqrt(pi)*gamma(n+S(3)/2)*a**n*s*(s**2+a**2)**(-n-S(3)/2),
  467. And(re(n) > -1, Eq(b, n+1)), Abs(im(a)), dco), # 4.14.8
  468. # (besselj(0, 2*sqrt(a*t)), exp(-a/s)/s,
  469. # S.true, S.Zero, dco), # 4.14.25
  470. # (t**(b)*besselj(n, 2*sqrt(a*t)), a**(n/2)*s**(-n-1)*exp(-a/s),
  471. # And(re(n) > -1, Eq(b, n*S.Half)), S.Zero, dco), # 4.14.30
  472. (besselj(0, a*sqrt(t**2+b*t)),
  473. exp(b*s-b*sqrt(s**2+a**2))/sqrt(s**2+a**2),
  474. Abs(arg(b)) < pi, Abs(im(a)), dco), # 4.15.19
  475. (besseli(n, a*t), a**n/(sqrt(s**2-a**2)*(s+sqrt(s**2-a**2))**n),
  476. re(n) > -1, Abs(re(a)), dco), # 4.16.1
  477. (t**b*besseli(n, a*t),
  478. 2**n/sqrt(pi)*gamma(n+S.Half)*a**n*(s**2-a**2)**(-n-S.Half),
  479. And(re(n) > -S.Half, Eq(b, n)), Abs(re(a)), dco), # 4.16.6
  480. (t**b*besseli(n, a*t),
  481. 2**(n+1)/sqrt(pi)*gamma(n+S(3)/2)*a**n*s*(s**2-a**2)**(-n-S(3)/2),
  482. And(re(n) > -1, Eq(b, n+1)), Abs(re(a)), dco), # 4.16.7
  483. # (t**(b)*besseli(n, 2*sqrt(a*t)), a**(n/2)*s**(-n-1)*exp(a/s),
  484. # And(re(n) > -1, Eq(b, n*S.Half)), S.Zero, dco), # 4.16.18
  485. (bessely(0, a*t), -2/pi*asinh(s/a)/sqrt(s**2+a**2),
  486. S.true, Abs(im(a)), dco), # 4.15.44
  487. (besselk(0, a*t), log((s + sqrt(s**2-a**2))/a)/(sqrt(s**2-a**2)),
  488. S.true, -re(a), dco) # 4.16.23
  489. ]
  490. return laplace_transform_rules, t, s
  491. @DEBUG_WRAP
  492. def _laplace_rule_timescale(f, t, s):
  493. """
  494. This function applies the time-scaling rule of the Laplace transform in
  495. a straight-forward way. For example, if it gets ``(f(a*t), t, s)``, it will
  496. compute ``LaplaceTransform(f(t)/a, t, s/a)`` if ``a>0``.
  497. """
  498. a = Wild('a', exclude=[t])
  499. g = WildFunction('g', nargs=1)
  500. ma1 = f.match(g)
  501. if ma1:
  502. arg = ma1[g].args[0].collect(t)
  503. ma2 = arg.match(a*t)
  504. if ma2 and ma2[a].is_positive and ma2[a] != 1:
  505. _debug(' rule: time scaling (4.1.4)')
  506. r, pr, cr = _laplace_transform(
  507. 1/ma2[a]*ma1[g].func(t), t, s/ma2[a], simplify=False)
  508. return (r, pr, cr)
  509. return None
  510. @DEBUG_WRAP
  511. def _laplace_rule_heaviside(f, t, s):
  512. """
  513. This function deals with time-shifted Heaviside step functions. If the time
  514. shift is positive, it applies the time-shift rule of the Laplace transform.
  515. For example, if it gets ``(Heaviside(t-a)*f(t), t, s)``, it will compute
  516. ``exp(-a*s)*LaplaceTransform(f(t+a), t, s)``.
  517. If the time shift is negative, the Heaviside function is simply removed
  518. as it means nothing to the Laplace transform.
  519. The function does not remove a factor ``Heaviside(t)``; this is done by
  520. the simple rules.
  521. """
  522. a = Wild('a', exclude=[t])
  523. y = Wild('y')
  524. g = Wild('g')
  525. if ma1 := f.match(Heaviside(y) * g):
  526. if ma2 := ma1[y].match(t - a):
  527. if ma2[a].is_positive:
  528. _debug(' rule: time shift (4.1.4)')
  529. r, pr, cr = _laplace_transform(
  530. ma1[g].subs(t, t + ma2[a]), t, s, simplify=False)
  531. return (exp(-ma2[a] * s) * r, pr, cr)
  532. if ma2[a].is_negative:
  533. _debug(
  534. ' rule: Heaviside factor; negative time shift (4.1.4)')
  535. r, pr, cr = _laplace_transform(ma1[g], t, s, simplify=False)
  536. return (r, pr, cr)
  537. if ma2 := ma1[y].match(a - t):
  538. if ma2[a].is_positive:
  539. _debug(' rule: Heaviside window open')
  540. r, pr, cr = _laplace_transform(
  541. (1 - Heaviside(t - ma2[a])) * ma1[g], t, s, simplify=False)
  542. return (r, pr, cr)
  543. if ma2[a].is_negative:
  544. _debug(' rule: Heaviside window closed')
  545. return (0, 0, S.true)
  546. return None
  547. @DEBUG_WRAP
  548. def _laplace_rule_exp(f, t, s):
  549. """
  550. If this function finds a factor ``exp(a*t)``, it applies the
  551. frequency-shift rule of the Laplace transform and adjusts the convergence
  552. plane accordingly. For example, if it gets ``(exp(-a*t)*f(t), t, s)``, it
  553. will compute ``LaplaceTransform(f(t), t, s+a)``.
  554. """
  555. a = Wild('a', exclude=[t])
  556. y = Wild('y')
  557. z = Wild('z')
  558. ma1 = f.match(exp(y)*z)
  559. if ma1:
  560. ma2 = ma1[y].collect(t).match(a*t)
  561. if ma2:
  562. _debug(' rule: multiply with exp (4.1.5)')
  563. r, pr, cr = _laplace_transform(ma1[z], t, s-ma2[a],
  564. simplify=False)
  565. return (r, pr+re(ma2[a]), cr)
  566. return None
  567. @DEBUG_WRAP
  568. def _laplace_rule_delta(f, t, s):
  569. """
  570. If this function finds a factor ``DiracDelta(b*t-a)``, it applies the
  571. masking property of the delta distribution. For example, if it gets
  572. ``(DiracDelta(t-a)*f(t), t, s)``, it will return
  573. ``(f(a)*exp(-a*s), -a, True)``.
  574. """
  575. # This rule is not in Bateman54
  576. a = Wild('a', exclude=[t])
  577. b = Wild('b', exclude=[t])
  578. y = Wild('y')
  579. z = Wild('z')
  580. ma1 = f.match(DiracDelta(y)*z)
  581. if ma1 and not ma1[z].has(DiracDelta):
  582. ma2 = ma1[y].collect(t).match(b*t-a)
  583. if ma2:
  584. _debug(' rule: multiply with DiracDelta')
  585. loc = ma2[a]/ma2[b]
  586. if re(loc) >= 0 and im(loc) == 0:
  587. fn = exp(-ma2[a]/ma2[b]*s)*ma1[z]
  588. if fn.has(sin, cos):
  589. # Then it may be possible that a sinc() is present in the
  590. # term; let's try this:
  591. fn = fn.rewrite(sinc).ratsimp()
  592. n, d = [x.subs(t, ma2[a]/ma2[b]) for x in fn.as_numer_denom()]
  593. if d != 0:
  594. return (n/d/ma2[b], S.NegativeInfinity, S.true)
  595. else:
  596. return None
  597. else:
  598. return (0, S.NegativeInfinity, S.true)
  599. if ma1[y].is_polynomial(t):
  600. ro = roots(ma1[y], t)
  601. if ro != {} and set(ro.values()) == {1}:
  602. slope = diff(ma1[y], t)
  603. r = Add(
  604. *[exp(-x*s)*ma1[z].subs(t, s)/slope.subs(t, x)
  605. for x in list(ro.keys()) if im(x) == 0 and re(x) >= 0])
  606. return (r, S.NegativeInfinity, S.true)
  607. return None
  608. @DEBUG_WRAP
  609. def _laplace_trig_split(fn):
  610. """
  611. Helper function for `_laplace_rule_trig`. This function returns two terms
  612. `f` and `g`. `f` contains all product terms with sin, cos, sinh, cosh in
  613. them; `g` contains everything else.
  614. """
  615. trigs = [S.One]
  616. other = [S.One]
  617. for term in Mul.make_args(fn):
  618. if term.has(sin, cos, sinh, cosh, exp):
  619. trigs.append(term)
  620. else:
  621. other.append(term)
  622. f = Mul(*trigs)
  623. g = Mul(*other)
  624. return f, g
  625. @DEBUG_WRAP
  626. def _laplace_trig_expsum(f, t):
  627. """
  628. Helper function for `_laplace_rule_trig`. This function expects the `f`
  629. from `_laplace_trig_split`. It returns two lists `xm` and `xn`. `xm` is
  630. a list of dictionaries with keys `k` and `a` representing a function
  631. `k*exp(a*t)`. `xn` is a list of all terms that cannot be brought into
  632. that form, which may happen, e.g., when a trigonometric function has
  633. another function in its argument.
  634. """
  635. c1 = Wild('c1', exclude=[t])
  636. c0 = Wild('c0', exclude=[t])
  637. p = Wild('p', exclude=[t])
  638. xm = []
  639. xn = []
  640. x1 = f.rewrite(exp).expand()
  641. for term in Add.make_args(x1):
  642. if not term.has(t):
  643. xm.append({'k': term, 'a': 0, re: 0, im: 0})
  644. continue
  645. term = _laplace_deep_collect(term.powsimp(combine='exp'), t)
  646. if (r := term.match(p*exp(c1*t+c0))) is not None:
  647. xm.append({
  648. 'k': r[p]*exp(r[c0]), 'a': r[c1],
  649. re: re(r[c1]), im: im(r[c1])})
  650. else:
  651. xn.append(term)
  652. return xm, xn
  653. @DEBUG_WRAP
  654. def _laplace_trig_ltex(xm, t, s):
  655. """
  656. Helper function for `_laplace_rule_trig`. This function takes the list of
  657. exponentials `xm` from `_laplace_trig_expsum` and simplifies complex
  658. conjugate and real symmetric poles. It returns the result as a sum and
  659. the convergence plane.
  660. """
  661. results = []
  662. planes = []
  663. def _simpc(coeffs):
  664. nc = coeffs.copy()
  665. for k in range(len(nc)):
  666. ri = nc[k].as_real_imag()
  667. if ri[0].has(im):
  668. nc[k] = nc[k].rewrite(cos)
  669. else:
  670. nc[k] = (ri[0] + I*ri[1]).rewrite(cos)
  671. return nc
  672. def _quadpole(t1, k1, k2, k3, s):
  673. a, k0, a_r, a_i = t1['a'], t1['k'], t1[re], t1[im]
  674. nc = [
  675. k0 + k1 + k2 + k3,
  676. a*(k0 + k1 - k2 - k3) - 2*I*a_i*k1 + 2*I*a_i*k2,
  677. (
  678. a**2*(-k0 - k1 - k2 - k3) +
  679. a*(4*I*a_i*k0 + 4*I*a_i*k3) +
  680. 4*a_i**2*k0 + 4*a_i**2*k3),
  681. (
  682. a**3*(-k0 - k1 + k2 + k3) +
  683. a**2*(4*I*a_i*k0 + 2*I*a_i*k1 - 2*I*a_i*k2 - 4*I*a_i*k3) +
  684. a*(4*a_i**2*k0 - 4*a_i**2*k3))
  685. ]
  686. dc = [
  687. S.One, S.Zero, 2*a_i**2 - 2*a_r**2,
  688. S.Zero, a_i**4 + 2*a_i**2*a_r**2 + a_r**4]
  689. n = Add(
  690. *[x*s**y for x, y in zip(_simpc(nc), range(len(nc))[::-1])])
  691. d = Add(
  692. *[x*s**y for x, y in zip(dc, range(len(dc))[::-1])])
  693. return n/d
  694. def _ccpole(t1, k1, s):
  695. a, k0, a_r, a_i = t1['a'], t1['k'], t1[re], t1[im]
  696. nc = [k0 + k1, -a*k0 - a*k1 + 2*I*a_i*k0]
  697. dc = [S.One, -2*a_r, a_i**2 + a_r**2]
  698. n = Add(
  699. *[x*s**y for x, y in zip(_simpc(nc), range(len(nc))[::-1])])
  700. d = Add(
  701. *[x*s**y for x, y in zip(dc, range(len(dc))[::-1])])
  702. return n/d
  703. def _rspole(t1, k2, s):
  704. a, k0, a_r, a_i = t1['a'], t1['k'], t1[re], t1[im]
  705. nc = [k0 + k2, a*k0 - a*k2 - 2*I*a_i*k0]
  706. dc = [S.One, -2*I*a_i, -a_i**2 - a_r**2]
  707. n = Add(
  708. *[x*s**y for x, y in zip(_simpc(nc), range(len(nc))[::-1])])
  709. d = Add(
  710. *[x*s**y for x, y in zip(dc, range(len(dc))[::-1])])
  711. return n/d
  712. def _sypole(t1, k3, s):
  713. a, k0 = t1['a'], t1['k']
  714. nc = [k0 + k3, a*(k0 - k3)]
  715. dc = [S.One, S.Zero, -a**2]
  716. n = Add(
  717. *[x*s**y for x, y in zip(_simpc(nc), range(len(nc))[::-1])])
  718. d = Add(
  719. *[x*s**y for x, y in zip(dc, range(len(dc))[::-1])])
  720. return n/d
  721. def _simplepole(t1, s):
  722. a, k0 = t1['a'], t1['k']
  723. n = k0
  724. d = s - a
  725. return n/d
  726. while len(xm) > 0:
  727. t1 = xm.pop()
  728. i_imagsym = None
  729. i_realsym = None
  730. i_pointsym = None
  731. # The following code checks all remaining poles. If t1 is a pole at
  732. # a+b*I, then we check for a-b*I, -a+b*I, and -a-b*I, and
  733. # assign the respective indices to i_imagsym, i_realsym, i_pointsym.
  734. # -a-b*I / i_pointsym only applies if both a and b are != 0.
  735. for i in range(len(xm)):
  736. real_eq = t1[re] == xm[i][re]
  737. realsym = t1[re] == -xm[i][re]
  738. imag_eq = t1[im] == xm[i][im]
  739. imagsym = t1[im] == -xm[i][im]
  740. if realsym and imagsym and t1[re] != 0 and t1[im] != 0:
  741. i_pointsym = i
  742. elif realsym and imag_eq and t1[re] != 0:
  743. i_realsym = i
  744. elif real_eq and imagsym and t1[im] != 0:
  745. i_imagsym = i
  746. # The next part looks for four possible pole constellations:
  747. # quad: a+b*I, a-b*I, -a+b*I, -a-b*I
  748. # cc: a+b*I, a-b*I (a may be zero)
  749. # quad: a+b*I, -a+b*I (b may be zero)
  750. # point: a+b*I, -a-b*I (a!=0 and b!=0 is needed, but that has been
  751. # asserted when finding i_pointsym above.)
  752. # If none apply, then t1 is a simple pole.
  753. if (
  754. i_imagsym is not None and i_realsym is not None
  755. and i_pointsym is not None):
  756. results.append(
  757. _quadpole(t1,
  758. xm[i_imagsym]['k'], xm[i_realsym]['k'],
  759. xm[i_pointsym]['k'], s))
  760. planes.append(Abs(re(t1['a'])))
  761. # The three additional poles have now been used; to pop them
  762. # easily we have to do it from the back.
  763. indices_to_pop = [i_imagsym, i_realsym, i_pointsym]
  764. indices_to_pop.sort(reverse=True)
  765. for i in indices_to_pop:
  766. xm.pop(i)
  767. elif i_imagsym is not None:
  768. results.append(_ccpole(t1, xm[i_imagsym]['k'], s))
  769. planes.append(t1[re])
  770. xm.pop(i_imagsym)
  771. elif i_realsym is not None:
  772. results.append(_rspole(t1, xm[i_realsym]['k'], s))
  773. planes.append(Abs(t1[re]))
  774. xm.pop(i_realsym)
  775. elif i_pointsym is not None:
  776. results.append(_sypole(t1, xm[i_pointsym]['k'], s))
  777. planes.append(Abs(t1[re]))
  778. xm.pop(i_pointsym)
  779. else:
  780. results.append(_simplepole(t1, s))
  781. planes.append(t1[re])
  782. return Add(*results), Max(*planes)
  783. @DEBUG_WRAP
  784. def _laplace_rule_trig(fn, t_, s):
  785. """
  786. This rule covers trigonometric factors by splitting everything into a
  787. sum of exponential functions and collecting complex conjugate poles and
  788. real symmetric poles.
  789. """
  790. t = Dummy('t', real=True)
  791. if not fn.has(sin, cos, sinh, cosh):
  792. return None
  793. f, g = _laplace_trig_split(fn.subs(t_, t))
  794. xm, xn = _laplace_trig_expsum(f, t)
  795. if len(xn) > 0:
  796. # TODO not implemented yet, but also not important
  797. return None
  798. if not g.has(t):
  799. r, p = _laplace_trig_ltex(xm, t, s)
  800. return g*r, p, S.true
  801. else:
  802. # Just transform `g` and make frequency-shifted copies
  803. planes = []
  804. results = []
  805. G, G_plane, G_cond = _laplace_transform(g, t, s, simplify=False)
  806. for x1 in xm:
  807. results.append(x1['k']*G.subs(s, s-x1['a']))
  808. planes.append(G_plane+re(x1['a']))
  809. return Add(*results).subs(t, t_), Max(*planes), G_cond
  810. @DEBUG_WRAP
  811. def _laplace_rule_diff(f, t, s):
  812. """
  813. This function looks for derivatives in the time domain and replaces it
  814. by factors of `s` and initial conditions in the frequency domain. For
  815. example, if it gets ``(diff(f(t), t), t, s)``, it will compute
  816. ``s*LaplaceTransform(f(t), t, s) - f(0)``.
  817. """
  818. a = Wild('a', exclude=[t])
  819. n = Wild('n', exclude=[t])
  820. g = WildFunction('g')
  821. ma1 = f.match(a*Derivative(g, (t, n)))
  822. if ma1 and ma1[n].is_integer:
  823. m = [z.has(t) for z in ma1[g].args]
  824. if sum(m) == 1:
  825. _debug(' rule: time derivative (4.1.8)')
  826. d = []
  827. for k in range(ma1[n]):
  828. if k == 0:
  829. y = ma1[g].subs(t, 0)
  830. else:
  831. y = Derivative(ma1[g], (t, k)).subs(t, 0)
  832. d.append(s**(ma1[n]-k-1)*y)
  833. r, pr, cr = _laplace_transform(ma1[g], t, s, simplify=False)
  834. return (ma1[a]*(s**ma1[n]*r - Add(*d)), pr, cr)
  835. return None
  836. @DEBUG_WRAP
  837. def _laplace_rule_sdiff(f, t, s):
  838. """
  839. This function looks for multiplications with polynoimials in `t` as they
  840. correspond to differentiation in the frequency domain. For example, if it
  841. gets ``(t*f(t), t, s)``, it will compute
  842. ``-Derivative(LaplaceTransform(f(t), t, s), s)``.
  843. """
  844. if f.is_Mul:
  845. pfac = [1]
  846. ofac = [1]
  847. for fac in Mul.make_args(f):
  848. if fac.is_polynomial(t):
  849. pfac.append(fac)
  850. else:
  851. ofac.append(fac)
  852. if len(pfac) > 1:
  853. pex = prod(pfac)
  854. pc = Poly(pex, t).all_coeffs()
  855. N = len(pc)
  856. if N > 1:
  857. oex = prod(ofac)
  858. r_, p_, c_ = _laplace_transform(oex, t, s, simplify=False)
  859. deri = [r_]
  860. d1 = False
  861. try:
  862. d1 = -diff(deri[-1], s)
  863. except ValueError:
  864. d1 = False
  865. if r_.has(LaplaceTransform):
  866. for k in range(N-1):
  867. deri.append((-1)**(k+1)*Derivative(r_, s, k+1))
  868. elif d1:
  869. deri.append(d1)
  870. for k in range(N-2):
  871. deri.append(-diff(deri[-1], s))
  872. if d1:
  873. r = Add(*[pc[N-n-1]*deri[n] for n in range(N)])
  874. return (r, p_, c_)
  875. # We still have to cover the possibility that there is a symbolic positive
  876. # integer exponent.
  877. n = Wild('n', exclude=[t])
  878. g = Wild('g')
  879. if ma1 := f.match(t**n*g):
  880. if ma1[n].is_integer and ma1[n].is_positive:
  881. r_, p_, c_ = _laplace_transform(ma1[g], t, s, simplify=False)
  882. return (-1)**ma1[n]*diff(r_, (s, ma1[n])), p_, c_
  883. return None
  884. @DEBUG_WRAP
  885. def _laplace_expand(f, t, s):
  886. """
  887. This function tries to expand its argument with successively stronger
  888. methods: first it will expand on the top level, then it will expand any
  889. multiplications in depth, then it will try all available expansion methods,
  890. and finally it will try to expand trigonometric functions.
  891. If it can expand, it will then compute the Laplace transform of the
  892. expanded term.
  893. """
  894. r = expand(f, deep=False)
  895. if r.is_Add:
  896. return _laplace_transform(r, t, s, simplify=False)
  897. r = expand_mul(f)
  898. if r.is_Add:
  899. return _laplace_transform(r, t, s, simplify=False)
  900. r = expand(f)
  901. if r.is_Add:
  902. return _laplace_transform(r, t, s, simplify=False)
  903. if r != f:
  904. return _laplace_transform(r, t, s, simplify=False)
  905. r = expand(expand_trig(f))
  906. if r.is_Add:
  907. return _laplace_transform(r, t, s, simplify=False)
  908. return None
  909. @DEBUG_WRAP
  910. def _laplace_apply_prog_rules(f, t, s):
  911. """
  912. This function applies all program rules and returns the result if one
  913. of them gives a result.
  914. """
  915. prog_rules = [_laplace_rule_heaviside, _laplace_rule_delta,
  916. _laplace_rule_timescale, _laplace_rule_exp,
  917. _laplace_rule_trig,
  918. _laplace_rule_diff, _laplace_rule_sdiff]
  919. for p_rule in prog_rules:
  920. if (L := p_rule(f, t, s)) is not None:
  921. return L
  922. return None
  923. @DEBUG_WRAP
  924. def _laplace_apply_simple_rules(f, t, s):
  925. """
  926. This function applies all simple rules and returns the result if one
  927. of them gives a result.
  928. """
  929. simple_rules, t_, s_ = _laplace_build_rules()
  930. prep_old = ''
  931. prep_f = ''
  932. for t_dom, s_dom, check, plane, prep in simple_rules:
  933. if prep_old != prep:
  934. prep_f = prep(f.subs({t: t_}))
  935. prep_old = prep
  936. ma = prep_f.match(t_dom)
  937. if ma:
  938. try:
  939. c = check.xreplace(ma)
  940. except TypeError:
  941. # This may happen if the time function has imaginary
  942. # numbers in it. Then we give up.
  943. continue
  944. if c == S.true:
  945. return (s_dom.xreplace(ma).subs({s_: s}),
  946. plane.xreplace(ma), S.true)
  947. return None
  948. @DEBUG_WRAP
  949. def _piecewise_to_heaviside(f, t):
  950. """
  951. This function converts a Piecewise expression to an expression written
  952. with Heaviside. It is not exact, but valid in the context of the Laplace
  953. transform.
  954. """
  955. if not t.is_real:
  956. r = Dummy('r', real=True)
  957. return _piecewise_to_heaviside(f.xreplace({t: r}), r).xreplace({r: t})
  958. x = piecewise_exclusive(f)
  959. r = []
  960. for fn, cond in x.args:
  961. # Here we do not need to do many checks because piecewise_exclusive
  962. # has a clearly predictable output. However, if any of the conditions
  963. # is not relative to t, this function just returns the input argument.
  964. if isinstance(cond, Relational) and t in cond.args:
  965. if isinstance(cond, (Eq, Ne)):
  966. # We do not cover this case; these would be single-point
  967. # exceptions that do not play a role in Laplace practice,
  968. # except if they contain Dirac impulses, and then we can
  969. # expect users to not try to use Piecewise for writing it.
  970. return f
  971. else:
  972. r.append(Heaviside(cond.gts - cond.lts)*fn)
  973. elif isinstance(cond, Or) and len(cond.args) == 2:
  974. # Or(t<2, t>4), Or(t>4, t<=2), ... in any order with any <= >=
  975. for c2 in cond.args:
  976. if c2.lhs == t:
  977. r.append(Heaviside(c2.gts - c2.lts)*fn)
  978. else:
  979. return f
  980. elif isinstance(cond, And) and len(cond.args) == 2:
  981. # And(t>2, t<4), And(t>4, t<=2), ... in any order with any <= >=
  982. c0, c1 = cond.args
  983. if c0.lhs == t and c1.lhs == t:
  984. if '>' in c0.rel_op:
  985. c0, c1 = c1, c0
  986. r.append(
  987. (Heaviside(c1.gts - c1.lts) -
  988. Heaviside(c0.lts - c0.gts))*fn)
  989. else:
  990. return f
  991. else:
  992. return f
  993. return Add(*r)
  994. def laplace_correspondence(f, fdict, /):
  995. """
  996. This helper function takes a function `f` that is the result of a
  997. ``laplace_transform`` or an ``inverse_laplace_transform``. It replaces all
  998. unevaluated ``LaplaceTransform(y(t), t, s)`` by `Y(s)` for any `s` and
  999. all ``InverseLaplaceTransform(Y(s), s, t)`` by `y(t)` for any `t` if
  1000. ``fdict`` contains a correspondence ``{y: Y}``.
  1001. Parameters
  1002. ==========
  1003. f : sympy expression
  1004. Expression containing unevaluated ``LaplaceTransform`` or
  1005. ``LaplaceTransform`` objects.
  1006. fdict : dictionary
  1007. Dictionary containing one or more function correspondences,
  1008. e.g., ``{x: X, y: Y}`` meaning that ``X`` and ``Y`` are the
  1009. Laplace transforms of ``x`` and ``y``, respectively.
  1010. Examples
  1011. ========
  1012. >>> from sympy import laplace_transform, diff, Function
  1013. >>> from sympy import laplace_correspondence, inverse_laplace_transform
  1014. >>> from sympy.abc import t, s
  1015. >>> y = Function("y")
  1016. >>> Y = Function("Y")
  1017. >>> z = Function("z")
  1018. >>> Z = Function("Z")
  1019. >>> f = laplace_transform(diff(y(t), t, 1) + z(t), t, s, noconds=True)
  1020. >>> laplace_correspondence(f, {y: Y, z: Z})
  1021. s*Y(s) + Z(s) - y(0)
  1022. >>> f = inverse_laplace_transform(Y(s), s, t)
  1023. >>> laplace_correspondence(f, {y: Y})
  1024. y(t)
  1025. """
  1026. p = Wild('p')
  1027. s = Wild('s')
  1028. t = Wild('t')
  1029. a = Wild('a')
  1030. if (
  1031. not isinstance(f, Expr)
  1032. or (not f.has(LaplaceTransform)
  1033. and not f.has(InverseLaplaceTransform))):
  1034. return f
  1035. for y, Y in fdict.items():
  1036. if (
  1037. (m := f.match(LaplaceTransform(y(a), t, s))) is not None
  1038. and m[a] == m[t]):
  1039. return Y(m[s])
  1040. if (
  1041. (m := f.match(InverseLaplaceTransform(Y(a), s, t, p)))
  1042. is not None
  1043. and m[a] == m[s]):
  1044. return y(m[t])
  1045. func = f.func
  1046. args = [laplace_correspondence(arg, fdict) for arg in f.args]
  1047. return func(*args)
  1048. def laplace_initial_conds(f, t, fdict, /):
  1049. """
  1050. This helper function takes a function `f` that is the result of a
  1051. ``laplace_transform``. It takes an fdict of the form ``{y: [1, 4, 2]}``,
  1052. where the values in the list are the initial value, the initial slope, the
  1053. initial second derivative, etc., of the function `y(t)`, and replaces all
  1054. unevaluated initial conditions.
  1055. Parameters
  1056. ==========
  1057. f : sympy expression
  1058. Expression containing initial conditions of unevaluated functions.
  1059. t : sympy expression
  1060. Variable for which the initial conditions are to be applied.
  1061. fdict : dictionary
  1062. Dictionary containing a list of initial conditions for every
  1063. function, e.g., ``{y: [0, 1, 2], x: [3, 4, 5]}``. The order
  1064. of derivatives is ascending, so `0`, `1`, `2` are `y(0)`, `y'(0)`,
  1065. and `y''(0)`, respectively.
  1066. Examples
  1067. ========
  1068. >>> from sympy import laplace_transform, diff, Function
  1069. >>> from sympy import laplace_correspondence, laplace_initial_conds
  1070. >>> from sympy.abc import t, s
  1071. >>> y = Function("y")
  1072. >>> Y = Function("Y")
  1073. >>> f = laplace_transform(diff(y(t), t, 3), t, s, noconds=True)
  1074. >>> g = laplace_correspondence(f, {y: Y})
  1075. >>> laplace_initial_conds(g, t, {y: [2, 4, 8, 16, 32]})
  1076. s**3*Y(s) - 2*s**2 - 4*s - 8
  1077. """
  1078. for y, ic in fdict.items():
  1079. for k in range(len(ic)):
  1080. if k == 0:
  1081. f = f.replace(y(0), ic[0])
  1082. elif k == 1:
  1083. f = f.replace(Subs(Derivative(y(t), t), t, 0), ic[1])
  1084. else:
  1085. f = f.replace(Subs(Derivative(y(t), (t, k)), t, 0), ic[k])
  1086. return f
  1087. @DEBUG_WRAP
  1088. def _laplace_transform(fn, t_, s_, *, simplify):
  1089. """
  1090. Front-end function of the Laplace transform. It tries to apply all known
  1091. rules recursively, and if everything else fails, it tries to integrate.
  1092. """
  1093. terms_t = Add.make_args(fn)
  1094. terms_s = []
  1095. terms = []
  1096. planes = []
  1097. conditions = []
  1098. for ff in terms_t:
  1099. k, ft = ff.as_independent(t_, as_Add=False)
  1100. if ft.has(SingularityFunction):
  1101. _terms = Add.make_args(ft.rewrite(Heaviside))
  1102. for _term in _terms:
  1103. k1, f1 = _term.as_independent(t_, as_Add=False)
  1104. terms.append((k*k1, f1))
  1105. elif ft.func == Piecewise and not ft.has(DiracDelta(t_)):
  1106. _terms = Add.make_args(_piecewise_to_heaviside(ft, t_))
  1107. for _term in _terms:
  1108. k1, f1 = _term.as_independent(t_, as_Add=False)
  1109. terms.append((k*k1, f1))
  1110. else:
  1111. terms.append((k, ft))
  1112. for k, ft in terms:
  1113. if ft.has(SingularityFunction):
  1114. r = (LaplaceTransform(ft, t_, s_), S.NegativeInfinity, True)
  1115. else:
  1116. if ft.has(Heaviside(t_)) and not ft.has(DiracDelta(t_)):
  1117. # For t>=0, Heaviside(t)=1 can be used, except if there is also
  1118. # a DiracDelta(t) present, in which case removing Heaviside(t)
  1119. # is unnecessary because _laplace_rule_delta can deal with it.
  1120. ft = ft.subs(Heaviside(t_), 1)
  1121. if (
  1122. (r := _laplace_apply_simple_rules(ft, t_, s_))
  1123. is not None or
  1124. (r := _laplace_apply_prog_rules(ft, t_, s_))
  1125. is not None or
  1126. (r := _laplace_expand(ft, t_, s_)) is not None):
  1127. pass
  1128. elif any(undef.has(t_) for undef in ft.atoms(AppliedUndef)):
  1129. # If there are undefined functions f(t) then integration is
  1130. # unlikely to do anything useful so we skip it and given an
  1131. # unevaluated LaplaceTransform.
  1132. r = (LaplaceTransform(ft, t_, s_), S.NegativeInfinity, True)
  1133. elif (r := _laplace_transform_integration(
  1134. ft, t_, s_, simplify=simplify)) is not None:
  1135. pass
  1136. else:
  1137. r = (LaplaceTransform(ft, t_, s_), S.NegativeInfinity, True)
  1138. (ri_, pi_, ci_) = r
  1139. terms_s.append(k*ri_)
  1140. planes.append(pi_)
  1141. conditions.append(ci_)
  1142. result = Add(*terms_s)
  1143. if simplify:
  1144. result = result.simplify(doit=False)
  1145. plane = Max(*planes)
  1146. condition = And(*conditions)
  1147. return result, plane, condition
  1148. class LaplaceTransform(IntegralTransform):
  1149. """
  1150. Class representing unevaluated Laplace transforms.
  1151. For usage of this class, see the :class:`IntegralTransform` docstring.
  1152. For how to compute Laplace transforms, see the :func:`laplace_transform`
  1153. docstring.
  1154. If this is called with ``.doit()``, it returns the Laplace transform as an
  1155. expression. If it is called with ``.doit(noconds=False)``, it returns a
  1156. tuple containing the same expression, a convergence plane, and conditions.
  1157. """
  1158. _name = 'Laplace'
  1159. def _compute_transform(self, f, t, s, **hints):
  1160. _simplify = hints.get('simplify', False)
  1161. LT = _laplace_transform_integration(f, t, s, simplify=_simplify)
  1162. return LT
  1163. def _as_integral(self, f, t, s):
  1164. return Integral(f*exp(-s*t), (t, S.Zero, S.Infinity))
  1165. def doit(self, **hints):
  1166. """
  1167. Try to evaluate the transform in closed form.
  1168. Explanation
  1169. ===========
  1170. Standard hints are the following:
  1171. - ``noconds``: if True, do not return convergence conditions. The
  1172. default setting is `True`.
  1173. - ``simplify``: if True, it simplifies the final result. The
  1174. default setting is `False`.
  1175. """
  1176. _noconds = hints.get('noconds', True)
  1177. _simplify = hints.get('simplify', False)
  1178. debugf('[LT doit] (%s, %s, %s)', (self.function,
  1179. self.function_variable,
  1180. self.transform_variable))
  1181. t_ = self.function_variable
  1182. s_ = self.transform_variable
  1183. fn = self.function
  1184. r = _laplace_transform(fn, t_, s_, simplify=_simplify)
  1185. if _noconds:
  1186. return r[0]
  1187. else:
  1188. return r
  1189. def laplace_transform(f, t, s, legacy_matrix=True, **hints):
  1190. r"""
  1191. Compute the Laplace Transform `F(s)` of `f(t)`,
  1192. .. math :: F(s) = \int_{0^{-}}^\infty e^{-st} f(t) \mathrm{d}t.
  1193. Explanation
  1194. ===========
  1195. For all sensible functions, this converges absolutely in a
  1196. half-plane
  1197. .. math :: a < \operatorname{Re}(s)
  1198. This function returns ``(F, a, cond)`` where ``F`` is the Laplace
  1199. transform of ``f``, `a` is the half-plane of convergence, and `cond` are
  1200. auxiliary convergence conditions.
  1201. The implementation is rule-based, and if you are interested in which
  1202. rules are applied, and whether integration is attempted, you can switch
  1203. debug information on by setting ``sympy.SYMPY_DEBUG=True``. The numbers
  1204. of the rules in the debug information (and the code) refer to Bateman's
  1205. Tables of Integral Transforms [1].
  1206. The lower bound is `0-`, meaning that this bound should be approached
  1207. from the lower side. This is only necessary if distributions are involved.
  1208. At present, it is only done if `f(t)` contains ``DiracDelta``, in which
  1209. case the Laplace transform is computed implicitly as
  1210. .. math ::
  1211. F(s) = \lim_{\tau\to 0^{-}} \int_{\tau}^\infty e^{-st}
  1212. f(t) \mathrm{d}t
  1213. by applying rules.
  1214. If the Laplace transform cannot be fully computed in closed form, this
  1215. function returns expressions containing unevaluated
  1216. :class:`LaplaceTransform` objects.
  1217. For a description of possible hints, refer to the docstring of
  1218. :func:`sympy.integrals.transforms.IntegralTransform.doit`. If
  1219. ``noconds=True``, only `F` will be returned (i.e. not ``cond``, and also
  1220. not the plane ``a``).
  1221. .. deprecated:: 1.9
  1222. Legacy behavior for matrices where ``laplace_transform`` with
  1223. ``noconds=False`` (the default) returns a Matrix whose elements are
  1224. tuples. The behavior of ``laplace_transform`` for matrices will change
  1225. in a future release of SymPy to return a tuple of the transformed
  1226. Matrix and the convergence conditions for the matrix as a whole. Use
  1227. ``legacy_matrix=False`` to enable the new behavior.
  1228. Examples
  1229. ========
  1230. >>> from sympy import DiracDelta, exp, laplace_transform
  1231. >>> from sympy.abc import t, s, a
  1232. >>> laplace_transform(t**4, t, s)
  1233. (24/s**5, 0, True)
  1234. >>> laplace_transform(t**a, t, s)
  1235. (gamma(a + 1)/(s*s**a), 0, re(a) > -1)
  1236. >>> laplace_transform(DiracDelta(t)-a*exp(-a*t), t, s, simplify=True)
  1237. (s/(a + s), -re(a), True)
  1238. There are also helper functions that make it easy to solve differential
  1239. equations by Laplace transform. For example, to solve
  1240. .. math :: m x''(t) + d x'(t) + k x(t) = 0
  1241. with initial value `0` and initial derivative `v`:
  1242. >>> from sympy import Function, laplace_correspondence, diff, solve
  1243. >>> from sympy import laplace_initial_conds, inverse_laplace_transform
  1244. >>> from sympy.abc import d, k, m, v
  1245. >>> x = Function('x')
  1246. >>> X = Function('X')
  1247. >>> f = m*diff(x(t), t, 2) + d*diff(x(t), t) + k*x(t)
  1248. >>> F = laplace_transform(f, t, s, noconds=True)
  1249. >>> F = laplace_correspondence(F, {x: X})
  1250. >>> F = laplace_initial_conds(F, t, {x: [0, v]})
  1251. >>> F
  1252. d*s*X(s) + k*X(s) + m*(s**2*X(s) - v)
  1253. >>> Xs = solve(F, X(s))[0]
  1254. >>> Xs
  1255. m*v/(d*s + k + m*s**2)
  1256. >>> inverse_laplace_transform(Xs, s, t)
  1257. 2*v*exp(-d*t/(2*m))*sin(t*sqrt((-d**2 + 4*k*m)/m**2)/2)*Heaviside(t)/sqrt((-d**2 + 4*k*m)/m**2)
  1258. References
  1259. ==========
  1260. .. [1] Erdelyi, A. (ed.), Tables of Integral Transforms, Volume 1,
  1261. Bateman Manuscript Prooject, McGraw-Hill (1954), available:
  1262. https://resolver.caltech.edu/CaltechAUTHORS:20140123-101456353
  1263. See Also
  1264. ========
  1265. inverse_laplace_transform, mellin_transform, fourier_transform
  1266. hankel_transform, inverse_hankel_transform
  1267. """
  1268. _noconds = hints.get('noconds', False)
  1269. _simplify = hints.get('simplify', False)
  1270. if isinstance(f, MatrixBase) and hasattr(f, 'applyfunc'):
  1271. conds = not hints.get('noconds', False)
  1272. if conds and legacy_matrix:
  1273. adt = 'deprecated-laplace-transform-matrix'
  1274. sympy_deprecation_warning(
  1275. """
  1276. Calling laplace_transform() on a Matrix with noconds=False (the default) is
  1277. deprecated. Either noconds=True or use legacy_matrix=False to get the new
  1278. behavior.
  1279. """,
  1280. deprecated_since_version='1.9',
  1281. active_deprecations_target=adt,
  1282. )
  1283. # Temporarily disable the deprecation warning for non-Expr objects
  1284. # in Matrix
  1285. with ignore_warnings(SymPyDeprecationWarning):
  1286. return f.applyfunc(
  1287. lambda fij: laplace_transform(fij, t, s, **hints))
  1288. else:
  1289. elements_trans = [laplace_transform(
  1290. fij, t, s, **hints) for fij in f]
  1291. if conds:
  1292. elements, avals, conditions = zip(*elements_trans)
  1293. f_laplace = type(f)(*f.shape, elements)
  1294. return f_laplace, Max(*avals), And(*conditions)
  1295. else:
  1296. return type(f)(*f.shape, elements_trans)
  1297. LT, p, c = LaplaceTransform(f, t, s).doit(noconds=False,
  1298. simplify=_simplify)
  1299. if not _noconds:
  1300. return LT, p, c
  1301. else:
  1302. return LT
  1303. @DEBUG_WRAP
  1304. def _inverse_laplace_transform_integration(F, s, t_, plane, *, simplify):
  1305. """ The backend function for inverse Laplace transforms. """
  1306. from sympy.integrals.meijerint import meijerint_inversion, _get_coeff_exp
  1307. from sympy.integrals.transforms import inverse_mellin_transform
  1308. # There are two strategies we can try:
  1309. # 1) Use inverse mellin transform, related by a simple change of variables.
  1310. # 2) Use the inversion integral.
  1311. t = Dummy('t', real=True)
  1312. def pw_simp(*args):
  1313. """ Simplify a piecewise expression from hyperexpand. """
  1314. if len(args) != 3:
  1315. return Piecewise(*args)
  1316. arg = args[2].args[0].argument
  1317. coeff, exponent = _get_coeff_exp(arg, t)
  1318. e1 = args[0].args[0]
  1319. e2 = args[1].args[0]
  1320. return (
  1321. Heaviside(1/Abs(coeff) - t**exponent)*e1 +
  1322. Heaviside(t**exponent - 1/Abs(coeff))*e2)
  1323. if F.is_rational_function(s):
  1324. F = F.apart(s)
  1325. if F.is_Add:
  1326. f = Add(
  1327. *[_inverse_laplace_transform_integration(X, s, t, plane, simplify)
  1328. for X in F.args])
  1329. return _simplify(f.subs(t, t_), simplify), True
  1330. try:
  1331. f, cond = inverse_mellin_transform(F, s, exp(-t), (None, S.Infinity),
  1332. needeval=True, noconds=False)
  1333. except IntegralTransformError:
  1334. f = None
  1335. if f is None:
  1336. f = meijerint_inversion(F, s, t)
  1337. if f is None:
  1338. return None
  1339. if f.is_Piecewise:
  1340. f, cond = f.args[0]
  1341. if f.has(Integral):
  1342. return None
  1343. else:
  1344. cond = S.true
  1345. f = f.replace(Piecewise, pw_simp)
  1346. if f.is_Piecewise:
  1347. # many of the functions called below can't work with piecewise
  1348. # (b/c it has a bool in args)
  1349. return f.subs(t, t_), cond
  1350. u = Dummy('u')
  1351. def simp_heaviside(arg, H0=S.Half):
  1352. a = arg.subs(exp(-t), u)
  1353. if a.has(t):
  1354. return Heaviside(arg, H0)
  1355. from sympy.solvers.inequalities import _solve_inequality
  1356. rel = _solve_inequality(a > 0, u)
  1357. if rel.lts == u:
  1358. k = log(rel.gts)
  1359. return Heaviside(t + k, H0)
  1360. else:
  1361. k = log(rel.lts)
  1362. return Heaviside(-(t + k), H0)
  1363. f = f.replace(Heaviside, simp_heaviside)
  1364. def simp_exp(arg):
  1365. return expand_complex(exp(arg))
  1366. f = f.replace(exp, simp_exp)
  1367. return _simplify(f.subs(t, t_), simplify), cond
  1368. @DEBUG_WRAP
  1369. def _complete_the_square_in_denom(f, s):
  1370. from sympy.simplify.radsimp import fraction
  1371. [n, d] = fraction(f)
  1372. if d.is_polynomial(s):
  1373. cf = d.as_poly(s).all_coeffs()
  1374. if len(cf) == 3:
  1375. a, b, c = cf
  1376. d = a*((s+b/(2*a))**2+c/a-(b/(2*a))**2)
  1377. return n/d
  1378. @cacheit
  1379. def _inverse_laplace_build_rules():
  1380. """
  1381. This is an internal helper function that returns the table of inverse
  1382. Laplace transform rules in terms of the time variable `t` and the
  1383. frequency variable `s`. It is used by `_inverse_laplace_apply_rules`.
  1384. """
  1385. s = Dummy('s')
  1386. t = Dummy('t')
  1387. a = Wild('a', exclude=[s])
  1388. b = Wild('b', exclude=[s])
  1389. c = Wild('c', exclude=[s])
  1390. _debug('_inverse_laplace_build_rules is building rules')
  1391. def _frac(f, s):
  1392. try:
  1393. return f.factor(s)
  1394. except PolynomialError:
  1395. return f
  1396. def same(f): return f
  1397. # This list is sorted according to the prep function needed.
  1398. _ILT_rules = [
  1399. (a/s, a, S.true, same, 1),
  1400. (
  1401. b*(s+a)**(-c), t**(c-1)*exp(-a*t)/gamma(c),
  1402. S.true, same, 1),
  1403. (1/(s**2+a**2)**2, (sin(a*t) - a*t*cos(a*t))/(2*a**3),
  1404. S.true, same, 1),
  1405. # The next two rules must be there in that order. For the second
  1406. # one, the condition would be a != 0 or, respectively, to take the
  1407. # limit a -> 0 after the transform if a == 0. It is much simpler if
  1408. # the case a == 0 has its own rule.
  1409. (1/(s**b), t**(b - 1)/gamma(b), S.true, same, 1),
  1410. (1/(s*(s+a)**b), lowergamma(b, a*t)/(a**b*gamma(b)),
  1411. S.true, same, 1)
  1412. ]
  1413. return _ILT_rules, s, t
  1414. @DEBUG_WRAP
  1415. def _inverse_laplace_apply_simple_rules(f, s, t):
  1416. """
  1417. Helper function for the class InverseLaplaceTransform.
  1418. """
  1419. if f == 1:
  1420. _debug(' rule: 1 o---o DiracDelta()')
  1421. return DiracDelta(t), S.true
  1422. _ILT_rules, s_, t_ = _inverse_laplace_build_rules()
  1423. _prep = ''
  1424. fsubs = f.subs({s: s_})
  1425. for s_dom, t_dom, check, prep, fac in _ILT_rules:
  1426. if _prep != (prep, fac):
  1427. _F = prep(fsubs*fac)
  1428. _prep = (prep, fac)
  1429. ma = _F.match(s_dom)
  1430. if ma:
  1431. c = check
  1432. if c is not S.true:
  1433. args = [x.xreplace(ma) for x in c[0]]
  1434. c = c[1](*args)
  1435. if c == S.true:
  1436. return Heaviside(t)*t_dom.xreplace(ma).subs({t_: t}), S.true
  1437. return None
  1438. @DEBUG_WRAP
  1439. def _inverse_laplace_diff(f, s, t, plane):
  1440. """
  1441. Helper function for the class InverseLaplaceTransform.
  1442. """
  1443. a = Wild('a', exclude=[s])
  1444. n = Wild('n', exclude=[s])
  1445. g = Wild('g')
  1446. ma = f.match(a*Derivative(g, (s, n)))
  1447. if ma and ma[n].is_integer:
  1448. _debug(' rule: t**n*f(t) o---o (-1)**n*diff(F(s), s, n)')
  1449. r, c = _inverse_laplace_transform(
  1450. ma[g], s, t, plane, simplify=False, dorational=False)
  1451. return (-t)**ma[n]*r, c
  1452. return None
  1453. @DEBUG_WRAP
  1454. def _inverse_laplace_time_shift(F, s, t, plane):
  1455. """
  1456. Helper function for the class InverseLaplaceTransform.
  1457. """
  1458. a = Wild('a', exclude=[s])
  1459. g = Wild('g')
  1460. if not F.has(s):
  1461. return F*DiracDelta(t), S.true
  1462. if not F.has(exp):
  1463. return None
  1464. ma1 = F.match(exp(a*s))
  1465. if ma1:
  1466. if ma1[a].is_negative:
  1467. _debug(' rule: exp(-a*s) o---o DiracDelta(t-a)')
  1468. return DiracDelta(t+ma1[a]), S.true
  1469. else:
  1470. return InverseLaplaceTransform(F, s, t, plane), S.true
  1471. ma1 = F.match(exp(a*s)*g)
  1472. if ma1:
  1473. if ma1[a].is_negative:
  1474. _debug(' rule: exp(-a*s)*F(s) o---o Heaviside(t-a)*f(t-a)')
  1475. return _inverse_laplace_transform(
  1476. ma1[g], s, t+ma1[a], plane, simplify=False, dorational=True)
  1477. else:
  1478. return InverseLaplaceTransform(F, s, t, plane), S.true
  1479. return None
  1480. @DEBUG_WRAP
  1481. def _inverse_laplace_freq_shift(F, s, t, plane):
  1482. """
  1483. Helper function for the class InverseLaplaceTransform.
  1484. """
  1485. if not F.has(s):
  1486. return F*DiracDelta(t), S.true
  1487. if len(args := F.args) == 1:
  1488. a = Wild('a', exclude=[s])
  1489. if (ma := args[0].match(s-a)) and re(ma[a]).is_positive:
  1490. _debug(' rule: F(s-a) o---o exp(-a*t)*f(t)')
  1491. return (
  1492. exp(-ma[a]*t) *
  1493. InverseLaplaceTransform(F.func(s), s, t, plane), S.true)
  1494. return None
  1495. @DEBUG_WRAP
  1496. def _inverse_laplace_time_diff(F, s, t, plane):
  1497. """
  1498. Helper function for the class InverseLaplaceTransform.
  1499. """
  1500. n = Wild('n', exclude=[s])
  1501. g = Wild('g')
  1502. ma1 = F.match(s**n*g)
  1503. if ma1 and ma1[n].is_integer and ma1[n].is_positive:
  1504. _debug(' rule: s**n*F(s) o---o diff(f(t), t, n)')
  1505. r, c = _inverse_laplace_transform(
  1506. ma1[g], s, t, plane, simplify=False, dorational=True)
  1507. r = r.replace(Heaviside(t), 1)
  1508. if r.has(InverseLaplaceTransform):
  1509. return diff(r, t, ma1[n]), c
  1510. else:
  1511. return Heaviside(t)*diff(r, t, ma1[n]), c
  1512. return None
  1513. @DEBUG_WRAP
  1514. def _inverse_laplace_irrational(fn, s, t, plane):
  1515. """
  1516. Helper function for the class InverseLaplaceTransform.
  1517. """
  1518. a = Wild('a', exclude=[s])
  1519. b = Wild('b', exclude=[s])
  1520. m = Wild('m', exclude=[s])
  1521. n = Wild('n', exclude=[s])
  1522. result = None
  1523. condition = S.true
  1524. fa = fn.as_ordered_factors()
  1525. ma = [x.match((a*s**m+b)**n) for x in fa]
  1526. if None in ma:
  1527. return None
  1528. constants = S.One
  1529. zeros = []
  1530. poles = []
  1531. rest = []
  1532. for term in ma:
  1533. if term[a] == 0:
  1534. constants = constants*term
  1535. elif term[n].is_positive:
  1536. zeros.append(term)
  1537. elif term[n].is_negative:
  1538. poles.append(term)
  1539. else:
  1540. rest.append(term)
  1541. # The code below assumes that the poles are sorted in a specific way:
  1542. poles = sorted(poles, key=lambda x: (x[n], x[b] != 0, x[b]))
  1543. zeros = sorted(zeros, key=lambda x: (x[n], x[b] != 0, x[b]))
  1544. if len(rest) != 0:
  1545. return None
  1546. if len(poles) == 1 and len(zeros) == 0:
  1547. if poles[0][n] == -1 and poles[0][m] == S.Half:
  1548. # 1/(a0*sqrt(s)+b0) == 1/a0 * 1/(sqrt(s)+b0/a0)
  1549. a_ = poles[0][b]/poles[0][a]
  1550. k_ = 1/poles[0][a]*constants
  1551. if a_.is_positive:
  1552. result = (
  1553. k_/sqrt(pi)/sqrt(t) -
  1554. k_*a_*exp(a_**2*t)*erfc(a_*sqrt(t)))
  1555. _debug(' rule 5.3.4')
  1556. elif poles[0][n] == -2 and poles[0][m] == S.Half:
  1557. # 1/(a0*sqrt(s)+b0)**2 == 1/a0**2 * 1/(sqrt(s)+b0/a0)**2
  1558. a_sq = poles[0][b]/poles[0][a]
  1559. a_ = a_sq**2
  1560. k_ = 1/poles[0][a]**2*constants
  1561. if a_sq.is_positive:
  1562. result = (
  1563. k_*(1 - 2/sqrt(pi)*sqrt(a_)*sqrt(t) +
  1564. (1-2*a_*t)*exp(a_*t)*(erf(sqrt(a_)*sqrt(t))-1)))
  1565. _debug(' rule 5.3.10')
  1566. elif poles[0][n] == -3 and poles[0][m] == S.Half:
  1567. # 1/(a0*sqrt(s)+b0)**3 == 1/a0**3 * 1/(sqrt(s)+b0/a0)**3
  1568. a_ = poles[0][b]/poles[0][a]
  1569. k_ = 1/poles[0][a]**3*constants
  1570. if a_.is_positive:
  1571. result = (
  1572. k_*(2/sqrt(pi)*(a_**2*t+1)*sqrt(t) -
  1573. a_*t*exp(a_**2*t)*(2*a_**2*t+3)*erfc(a_*sqrt(t))))
  1574. _debug(' rule 5.3.13')
  1575. elif poles[0][n] == -4 and poles[0][m] == S.Half:
  1576. # 1/(a0*sqrt(s)+b0)**4 == 1/a0**4 * 1/(sqrt(s)+b0/a0)**4
  1577. a_ = poles[0][b]/poles[0][a]
  1578. k_ = 1/poles[0][a]**4*constants/3
  1579. if a_.is_positive:
  1580. result = (
  1581. k_*(t*(4*a_**4*t**2+12*a_**2*t+3)*exp(a_**2*t) *
  1582. erfc(a_*sqrt(t)) -
  1583. 2/sqrt(pi)*a_**3*t**(S(5)/2)*(2*a_**2*t+5)))
  1584. _debug(' rule 5.3.16')
  1585. elif poles[0][n] == -S.Half and poles[0][m] == 2:
  1586. # 1/sqrt(a0*s**2+b0) == 1/sqrt(a0) * 1/sqrt(s**2+b0/a0)
  1587. a_ = sqrt(poles[0][b]/poles[0][a])
  1588. k_ = 1/sqrt(poles[0][a])*constants
  1589. result = (k_*(besselj(0, a_*t)))
  1590. _debug(' rule 5.3.35/44')
  1591. elif len(poles) == 1 and len(zeros) == 1:
  1592. if (
  1593. poles[0][n] == -3 and poles[0][m] == S.Half and
  1594. zeros[0][n] == S.Half and zeros[0][b] == 0):
  1595. # sqrt(az*s)/(ap*sqrt(s+bp)**3)
  1596. # == sqrt(az)/ap * sqrt(s)/(sqrt(s+bp)**3)
  1597. a_ = poles[0][b]
  1598. k_ = sqrt(zeros[0][a])/poles[0][a]*constants
  1599. result = (
  1600. k_*(2*a_**4*t**2+5*a_**2*t+1)*exp(a_**2*t) *
  1601. erfc(a_*sqrt(t)) - 2/sqrt(pi)*a_*(a_**2*t+2)*sqrt(t))
  1602. _debug(' rule 5.3.14')
  1603. if (
  1604. poles[0][n] == -1 and poles[0][m] == 1 and
  1605. zeros[0][n] == S.Half and zeros[0][m] == 1):
  1606. # sqrt(az*s+bz)/(ap*s+bp)
  1607. # == sqrt(az)/ap * (sqrt(s+bz/az)/(s+bp/ap))
  1608. a_ = zeros[0][b]/zeros[0][a]
  1609. b_ = poles[0][b]/poles[0][a]
  1610. k_ = sqrt(zeros[0][a])/poles[0][a]*constants
  1611. result = (
  1612. k_*(exp(-a_*t)/sqrt(t)/sqrt(pi)+sqrt(a_-b_) *
  1613. exp(-b_*t)*erf(sqrt(a_-b_)*sqrt(t))))
  1614. _debug(' rule 5.3.22')
  1615. elif len(poles) == 2 and len(zeros) == 0:
  1616. if (
  1617. poles[0][n] == -1 and poles[0][m] == 1 and
  1618. poles[1][n] == -S.Half and poles[1][m] == 1 and
  1619. poles[1][b] == 0):
  1620. # 1/((a0*s+b0)*sqrt(a1*s))
  1621. # == 1/(a0*sqrt(a1)) * 1/((s+b0/a0)*sqrt(s))
  1622. a_ = -poles[0][b]/poles[0][a]
  1623. k_ = 1/sqrt(poles[1][a])/poles[0][a]*constants
  1624. if a_.is_positive:
  1625. result = (k_/sqrt(a_)*exp(a_*t)*erf(sqrt(a_)*sqrt(t)))
  1626. _debug(' rule 5.3.1')
  1627. elif (
  1628. poles[0][n] == -1 and poles[0][m] == 1 and poles[0][b] == 0 and
  1629. poles[1][n] == -1 and poles[1][m] == S.Half):
  1630. # 1/(a0*s*(a1*sqrt(s)+b1))
  1631. # == 1/(a0*a1) * 1/(s*(sqrt(s)+b1/a1))
  1632. a_ = poles[1][b]/poles[1][a]
  1633. k_ = 1/poles[0][a]/poles[1][a]/a_*constants
  1634. if a_.is_positive:
  1635. result = k_*(1-exp(a_**2*t)*erfc(a_*sqrt(t)))
  1636. _debug(' rule 5.3.5')
  1637. elif (
  1638. poles[0][n] == -1 and poles[0][m] == S.Half and
  1639. poles[1][n] == -S.Half and poles[1][m] == 1 and
  1640. poles[1][b] == 0):
  1641. # 1/((a0*sqrt(s)+b0)*(sqrt(a1*s))
  1642. # == 1/(a0*sqrt(a1)) * 1/((sqrt(s)+b0/a0)"sqrt(s))
  1643. a_ = poles[0][b]/poles[0][a]
  1644. k_ = 1/(poles[0][a]*sqrt(poles[1][a]))*constants
  1645. if a_.is_positive:
  1646. result = k_*exp(a_**2*t)*erfc(a_*sqrt(t))
  1647. _debug(' rule 5.3.7')
  1648. elif (
  1649. poles[0][n] == -S(3)/2 and poles[0][m] == 1 and
  1650. poles[0][b] == 0 and poles[1][n] == -1 and
  1651. poles[1][m] == S.Half):
  1652. # 1/((a0**(3/2)*s**(3/2))*(a1*sqrt(s)+b1))
  1653. # == 1/(a0**(3/2)*a1) 1/((s**(3/2))*(sqrt(s)+b1/a1))
  1654. # Note that Bateman54 5.3 (8) is incorrect; there (sqrt(p)+a)
  1655. # should be (sqrt(p)+a)**(-1).
  1656. a_ = poles[1][b]/poles[1][a]
  1657. k_ = 1/(poles[0][a]**(S(3)/2)*poles[1][a])/a_**2*constants
  1658. if a_.is_positive:
  1659. result = (
  1660. k_*(2/sqrt(pi)*a_*sqrt(t)+exp(a_**2*t)*erfc(a_*sqrt(t))-1))
  1661. _debug(' rule 5.3.8')
  1662. elif (
  1663. poles[0][n] == -2 and poles[0][m] == S.Half and
  1664. poles[1][n] == -1 and poles[1][m] == 1 and
  1665. poles[1][b] == 0):
  1666. # 1/((a0*sqrt(s)+b0)**2*a1*s)
  1667. # == 1/a0**2/a1 * 1/(sqrt(s)+b0/a0)**2/s
  1668. a_sq = poles[0][b]/poles[0][a]
  1669. a_ = a_sq**2
  1670. k_ = 1/poles[0][a]**2/poles[1][a]*constants
  1671. if a_sq.is_positive:
  1672. result = (
  1673. k_*(1/a_ + (2*t-1/a_)*exp(a_*t)*erfc(sqrt(a_)*sqrt(t)) -
  1674. 2/sqrt(pi)/sqrt(a_)*sqrt(t)))
  1675. _debug(' rule 5.3.11')
  1676. elif (
  1677. poles[0][n] == -2 and poles[0][m] == S.Half and
  1678. poles[1][n] == -S.Half and poles[1][m] == 1 and
  1679. poles[1][b] == 0):
  1680. # 1/((a0*sqrt(s)+b0)**2*sqrt(a1*s))
  1681. # == 1/a0**2/sqrt(a1) * 1/(sqrt(s)+b0/a0)**2/sqrt(s)
  1682. a_ = poles[0][b]/poles[0][a]
  1683. k_ = 1/poles[0][a]**2/sqrt(poles[1][a])*constants
  1684. if a_.is_positive:
  1685. result = (
  1686. k_*(2/sqrt(pi)*sqrt(t) -
  1687. 2*a_*t*exp(a_**2*t)*erfc(a_*sqrt(t))))
  1688. _debug(' rule 5.3.12')
  1689. elif (
  1690. poles[0][n] == -3 and poles[0][m] == S.Half and
  1691. poles[1][n] == -S.Half and poles[1][m] == 1 and
  1692. poles[1][b] == 0):
  1693. # 1 / (sqrt(a1*s)*(a0*sqrt(s+b0)**3))
  1694. # == 1/(sqrt(a1)*a0) * 1/(sqrt(s)*(sqrt(s+b0)**3))
  1695. a_ = poles[0][b]
  1696. k_ = constants/sqrt(poles[1][a])/poles[0][a]
  1697. result = k_*(
  1698. (2*a_**2*t+1)*t*exp(a_**2*t)*erfc(a_*sqrt(t)) -
  1699. 2/sqrt(pi)*a_*t**(S(3)/2))
  1700. _debug(' rule 5.3.15')
  1701. elif (
  1702. poles[0][n] == -1 and poles[0][m] == 1 and
  1703. poles[1][n] == -S.Half and poles[1][m] == 1):
  1704. # 1 / ( (a0*s+b0)* sqrt(a1*s+b1) )
  1705. # == 1/(sqrt(a1)*a0) * 1 / ( (s+b0/a0)* sqrt(s+b1/a1) )
  1706. a_ = poles[0][b]/poles[0][a]
  1707. b_ = poles[1][b]/poles[1][a]
  1708. k_ = constants/sqrt(poles[1][a])/poles[0][a]
  1709. result = k_*(
  1710. 1/sqrt(b_-a_)*exp(-a_*t)*erf(sqrt(b_-a_)*sqrt(t)))
  1711. _debug(' rule 5.3.23')
  1712. elif len(poles) == 2 and len(zeros) == 1:
  1713. if (
  1714. poles[0][n] == -1 and poles[0][m] == 1 and
  1715. poles[1][n] == -1 and poles[1][m] == S.Half and
  1716. zeros[0][n] == S.Half and zeros[0][m] == 1 and
  1717. zeros[0][b] == 0):
  1718. # sqrt(za0*s)/((a0*s+b0)*(a1*sqrt(s)+b1))
  1719. # == sqrt(za0)/(a0*a1) * s/((s+b0/a0)*(sqrt(s)+b1/a1))
  1720. a_sq = poles[1][b]/poles[1][a]
  1721. a_ = a_sq**2
  1722. b_ = -poles[0][b]/poles[0][a]
  1723. k_ = sqrt(zeros[0][a])/poles[0][a]/poles[1][a]/(a_-b_)*constants
  1724. if a_sq.is_positive and b_.is_positive:
  1725. result = k_*(
  1726. a_*exp(a_*t)*erfc(sqrt(a_)*sqrt(t)) +
  1727. sqrt(a_)*sqrt(b_)*exp(b_*t)*erfc(sqrt(b_)*sqrt(t)) -
  1728. b_*exp(b_*t))
  1729. _debug(' rule 5.3.6')
  1730. elif (
  1731. poles[0][n] == -1 and poles[0][m] == 1 and
  1732. poles[0][b] == 0 and poles[1][n] == -1 and
  1733. poles[1][m] == S.Half and zeros[0][n] == 1 and
  1734. zeros[0][m] == S.Half):
  1735. # (az*sqrt(s)+bz)/(a0*s*(a1*sqrt(s)+b1))
  1736. # == az/a0/a1 * (sqrt(z)+bz/az)/(s*(sqrt(s)+b1/a1))
  1737. a_num = zeros[0][b]/zeros[0][a]
  1738. a_ = poles[1][b]/poles[1][a]
  1739. if a_+a_num == 0:
  1740. k_ = zeros[0][a]/poles[0][a]/poles[1][a]*constants
  1741. result = k_*(
  1742. 2*exp(a_**2*t)*erfc(a_*sqrt(t))-1)
  1743. _debug(' rule 5.3.17')
  1744. elif (
  1745. poles[1][n] == -1 and poles[1][m] == 1 and
  1746. poles[1][b] == 0 and poles[0][n] == -2 and
  1747. poles[0][m] == S.Half and zeros[0][n] == 2 and
  1748. zeros[0][m] == S.Half):
  1749. # (az*sqrt(s)+bz)**2/(a1*s*(a0*sqrt(s)+b0)**2)
  1750. # == az**2/a1/a0**2 * (sqrt(z)+bz/az)**2/(s*(sqrt(s)+b0/a0)**2)
  1751. a_num = zeros[0][b]/zeros[0][a]
  1752. a_ = poles[0][b]/poles[0][a]
  1753. if a_+a_num == 0:
  1754. k_ = zeros[0][a]**2/poles[1][a]/poles[0][a]**2*constants
  1755. result = k_*(
  1756. 1 + 8*a_**2*t*exp(a_**2*t)*erfc(a_*sqrt(t)) -
  1757. 8/sqrt(pi)*a_*sqrt(t))
  1758. _debug(' rule 5.3.18')
  1759. elif (
  1760. poles[1][n] == -1 and poles[1][m] == 1 and
  1761. poles[1][b] == 0 and poles[0][n] == -3 and
  1762. poles[0][m] == S.Half and zeros[0][n] == 3 and
  1763. zeros[0][m] == S.Half):
  1764. # (az*sqrt(s)+bz)**3/(a1*s*(a0*sqrt(s)+b0)**3)
  1765. # == az**3/a1/a0**3 * (sqrt(z)+bz/az)**3/(s*(sqrt(s)+b0/a0)**3)
  1766. a_num = zeros[0][b]/zeros[0][a]
  1767. a_ = poles[0][b]/poles[0][a]
  1768. if a_+a_num == 0:
  1769. k_ = zeros[0][a]**3/poles[1][a]/poles[0][a]**3*constants
  1770. result = k_*(
  1771. 2*(8*a_**4*t**2+8*a_**2*t+1)*exp(a_**2*t) *
  1772. erfc(a_*sqrt(t))-8/sqrt(pi)*a_*sqrt(t)*(2*a_**2*t+1)-1)
  1773. _debug(' rule 5.3.19')
  1774. elif len(poles) == 3 and len(zeros) == 0:
  1775. if (
  1776. poles[0][n] == -1 and poles[0][b] == 0 and poles[0][m] == 1 and
  1777. poles[1][n] == -1 and poles[1][m] == 1 and
  1778. poles[2][n] == -S.Half and poles[2][m] == 1):
  1779. # 1/((a0*s)*(a1*s+b1)*sqrt(a2*s))
  1780. # == 1/(a0*a1*sqrt(a2)) * 1/((s)*(s+b1/a1)*sqrt(s))
  1781. a_ = -poles[1][b]/poles[1][a]
  1782. k_ = 1/poles[0][a]/poles[1][a]/sqrt(poles[2][a])*constants
  1783. if a_.is_positive:
  1784. result = k_ * (
  1785. a_**(-S(3)/2) * exp(a_*t) * erf(sqrt(a_)*sqrt(t)) -
  1786. 2/a_/sqrt(pi)*sqrt(t))
  1787. _debug(' rule 5.3.2')
  1788. elif (
  1789. poles[0][n] == -1 and poles[0][m] == 1 and
  1790. poles[1][n] == -1 and poles[1][m] == S.Half and
  1791. poles[2][n] == -S.Half and poles[2][m] == 1 and
  1792. poles[2][b] == 0):
  1793. # 1/((a0*s+b0)*(a1*sqrt(s)+b1)*(sqrt(a2)*sqrt(s)))
  1794. # == 1/(a0*a1*sqrt(a2)) * 1/((s+b0/a0)*(sqrt(s)+b1/a1)*sqrt(s))
  1795. a_sq = poles[1][b]/poles[1][a]
  1796. a_ = a_sq**2
  1797. b_ = -poles[0][b]/poles[0][a]
  1798. k_ = (
  1799. 1/poles[0][a]/poles[1][a]/sqrt(poles[2][a]) /
  1800. (sqrt(b_)*(a_-b_)))
  1801. if a_sq.is_positive and b_.is_positive:
  1802. result = k_ * (
  1803. sqrt(b_)*exp(a_*t)*erfc(sqrt(a_)*sqrt(t)) +
  1804. sqrt(a_)*exp(b_*t)*erf(sqrt(b_)*sqrt(t)) -
  1805. sqrt(b_)*exp(b_*t))
  1806. _debug(' rule 5.3.9')
  1807. if result is None:
  1808. return None
  1809. else:
  1810. return Heaviside(t)*result, condition
  1811. @DEBUG_WRAP
  1812. def _inverse_laplace_early_prog_rules(F, s, t, plane):
  1813. """
  1814. Helper function for the class InverseLaplaceTransform.
  1815. """
  1816. prog_rules = [_inverse_laplace_irrational]
  1817. for p_rule in prog_rules:
  1818. if (r := p_rule(F, s, t, plane)) is not None:
  1819. return r
  1820. return None
  1821. @DEBUG_WRAP
  1822. def _inverse_laplace_apply_prog_rules(F, s, t, plane):
  1823. """
  1824. Helper function for the class InverseLaplaceTransform.
  1825. """
  1826. prog_rules = [_inverse_laplace_time_shift, _inverse_laplace_freq_shift,
  1827. _inverse_laplace_time_diff, _inverse_laplace_diff,
  1828. _inverse_laplace_irrational]
  1829. for p_rule in prog_rules:
  1830. if (r := p_rule(F, s, t, plane)) is not None:
  1831. return r
  1832. return None
  1833. @DEBUG_WRAP
  1834. def _inverse_laplace_expand(fn, s, t, plane):
  1835. """
  1836. Helper function for the class InverseLaplaceTransform.
  1837. """
  1838. if fn.is_Add:
  1839. return None
  1840. r = expand(fn, deep=False)
  1841. if r.is_Add:
  1842. return _inverse_laplace_transform(
  1843. r, s, t, plane, simplify=False, dorational=True)
  1844. r = expand_mul(fn)
  1845. if r.is_Add:
  1846. return _inverse_laplace_transform(
  1847. r, s, t, plane, simplify=False, dorational=True)
  1848. r = expand(fn)
  1849. if r.is_Add:
  1850. return _inverse_laplace_transform(
  1851. r, s, t, plane, simplify=False, dorational=True)
  1852. if fn.is_rational_function(s):
  1853. r = fn.apart(s).doit()
  1854. if r.is_Add:
  1855. return _inverse_laplace_transform(
  1856. r, s, t, plane, simplify=False, dorational=True)
  1857. return None
  1858. @DEBUG_WRAP
  1859. def _inverse_laplace_rational(fn, s, t, plane, *, simplify):
  1860. """
  1861. Helper function for the class InverseLaplaceTransform.
  1862. """
  1863. x_ = symbols('x_')
  1864. f = fn.apart(s)
  1865. terms = Add.make_args(f)
  1866. terms_t = []
  1867. conditions = [S.true]
  1868. for term in terms:
  1869. [n, d] = term.as_numer_denom()
  1870. dc = d.as_poly(s).all_coeffs()
  1871. dc_lead = dc[0]
  1872. dc = [x/dc_lead for x in dc]
  1873. nc = [x/dc_lead for x in n.as_poly(s).all_coeffs()]
  1874. if len(dc) == 1:
  1875. N = len(nc)-1
  1876. for c in enumerate(nc):
  1877. r = c[1]*DiracDelta(t, N-c[0])
  1878. terms_t.append(r)
  1879. elif len(dc) == 2:
  1880. r = nc[0]*exp(-dc[1]*t)
  1881. terms_t.append(Heaviside(t)*r)
  1882. elif len(dc) == 3:
  1883. a = dc[1]/2
  1884. b = (dc[2]-a**2).factor()
  1885. if len(nc) == 1:
  1886. nc = [S.Zero] + nc
  1887. l, m = tuple(nc)
  1888. if b == 0:
  1889. r = (m*t+l*(1-a*t))*exp(-a*t)
  1890. else:
  1891. hyp = False
  1892. if b.is_negative:
  1893. b = -b
  1894. hyp = True
  1895. b2 = list(roots(x_**2-b, x_).keys())[0]
  1896. bs = sqrt(b).simplify()
  1897. if hyp:
  1898. r = (
  1899. l*exp(-a*t)*cosh(b2*t) + (m-a*l) /
  1900. bs*exp(-a*t)*sinh(bs*t))
  1901. else:
  1902. r = l*exp(-a*t)*cos(b2*t) + (m-a*l)/bs*exp(-a*t)*sin(bs*t)
  1903. terms_t.append(Heaviside(t)*r)
  1904. else:
  1905. ft, cond = _inverse_laplace_transform(
  1906. term, s, t, plane, simplify=simplify, dorational=False)
  1907. terms_t.append(ft)
  1908. conditions.append(cond)
  1909. result = Add(*terms_t)
  1910. if simplify:
  1911. result = result.simplify(doit=False)
  1912. return result, And(*conditions)
  1913. @DEBUG_WRAP
  1914. def _inverse_laplace_transform(fn, s_, t_, plane, *, simplify, dorational):
  1915. """
  1916. Front-end function of the inverse Laplace transform. It tries to apply all
  1917. known rules recursively. If everything else fails, it tries to integrate.
  1918. """
  1919. terms = Add.make_args(fn)
  1920. terms_t = []
  1921. conditions = []
  1922. for term in terms:
  1923. if term.has(exp):
  1924. # Simplify expressions with exp() such that time-shifted
  1925. # expressions have negative exponents in the numerator instead of
  1926. # positive exponents in the numerator and denominator; this is a
  1927. # (necessary) trick. It will, for example, convert
  1928. # (s**2*exp(2*s) + 4*exp(s) - 4)*exp(-2*s)/(s*(s**2 + 1)) into
  1929. # (s**2 + 4*exp(-s) - 4*exp(-2*s))/(s*(s**2 + 1))
  1930. term = term.subs(s_, -s_).together().subs(s_, -s_)
  1931. k, f = term.as_independent(s_, as_Add=False)
  1932. if (
  1933. dorational and term.is_rational_function(s_) and
  1934. (r := _inverse_laplace_rational(
  1935. f, s_, t_, plane, simplify=simplify))
  1936. is not None or
  1937. (r := _inverse_laplace_apply_simple_rules(f, s_, t_))
  1938. is not None or
  1939. (r := _inverse_laplace_early_prog_rules(f, s_, t_, plane))
  1940. is not None or
  1941. (r := _inverse_laplace_expand(f, s_, t_, plane))
  1942. is not None or
  1943. (r := _inverse_laplace_apply_prog_rules(f, s_, t_, plane))
  1944. is not None):
  1945. pass
  1946. elif any(undef.has(s_) for undef in f.atoms(AppliedUndef)):
  1947. # If there are undefined functions f(t) then integration is
  1948. # unlikely to do anything useful so we skip it and given an
  1949. # unevaluated LaplaceTransform.
  1950. r = (InverseLaplaceTransform(f, s_, t_, plane), S.true)
  1951. elif (
  1952. r := _inverse_laplace_transform_integration(
  1953. f, s_, t_, plane, simplify=simplify)) is not None:
  1954. pass
  1955. else:
  1956. r = (InverseLaplaceTransform(f, s_, t_, plane), S.true)
  1957. (ri_, ci_) = r
  1958. terms_t.append(k*ri_)
  1959. conditions.append(ci_)
  1960. result = Add(*terms_t)
  1961. if simplify:
  1962. result = result.simplify(doit=False)
  1963. condition = And(*conditions)
  1964. return result, condition
  1965. class InverseLaplaceTransform(IntegralTransform):
  1966. """
  1967. Class representing unevaluated inverse Laplace transforms.
  1968. For usage of this class, see the :class:`IntegralTransform` docstring.
  1969. For how to compute inverse Laplace transforms, see the
  1970. :func:`inverse_laplace_transform` docstring.
  1971. """
  1972. _name = 'Inverse Laplace'
  1973. _none_sentinel = Dummy('None')
  1974. _c = Dummy('c')
  1975. def __new__(cls, F, s, x, plane, **opts):
  1976. if plane is None:
  1977. plane = InverseLaplaceTransform._none_sentinel
  1978. return IntegralTransform.__new__(cls, F, s, x, plane, **opts)
  1979. @property
  1980. def fundamental_plane(self):
  1981. plane = self.args[3]
  1982. if plane is InverseLaplaceTransform._none_sentinel:
  1983. plane = None
  1984. return plane
  1985. def _compute_transform(self, F, s, t, **hints):
  1986. return _inverse_laplace_transform_integration(
  1987. F, s, t, self.fundamental_plane, **hints)
  1988. def _as_integral(self, F, s, t):
  1989. c = self.__class__._c
  1990. return (
  1991. Integral(exp(s*t)*F, (s, c - S.ImaginaryUnit*S.Infinity,
  1992. c + S.ImaginaryUnit*S.Infinity)) /
  1993. (2*S.Pi*S.ImaginaryUnit))
  1994. def doit(self, **hints):
  1995. """
  1996. Try to evaluate the transform in closed form.
  1997. Explanation
  1998. ===========
  1999. Standard hints are the following:
  2000. - ``noconds``: if True, do not return convergence conditions. The
  2001. default setting is `True`.
  2002. - ``simplify``: if True, it simplifies the final result. The
  2003. default setting is `False`.
  2004. """
  2005. _noconds = hints.get('noconds', True)
  2006. _simplify = hints.get('simplify', False)
  2007. debugf('[ILT doit] (%s, %s, %s)', (self.function,
  2008. self.function_variable,
  2009. self.transform_variable))
  2010. s_ = self.function_variable
  2011. t_ = self.transform_variable
  2012. fn = self.function
  2013. plane = self.fundamental_plane
  2014. r = _inverse_laplace_transform(
  2015. fn, s_, t_, plane, simplify=_simplify, dorational=True)
  2016. if _noconds:
  2017. return r[0]
  2018. else:
  2019. return r
  2020. def inverse_laplace_transform(F, s, t, plane=None, **hints):
  2021. r"""
  2022. Compute the inverse Laplace transform of `F(s)`, defined as
  2023. .. math ::
  2024. f(t) = \frac{1}{2\pi i} \int_{c-i\infty}^{c+i\infty} e^{st}
  2025. F(s) \mathrm{d}s,
  2026. for `c` so large that `F(s)` has no singularites in the
  2027. half-plane `\operatorname{Re}(s) > c-\epsilon`.
  2028. Explanation
  2029. ===========
  2030. The plane can be specified by
  2031. argument ``plane``, but will be inferred if passed as None.
  2032. Under certain regularity conditions, this recovers `f(t)` from its
  2033. Laplace Transform `F(s)`, for non-negative `t`, and vice
  2034. versa.
  2035. If the integral cannot be computed in closed form, this function returns
  2036. an unevaluated :class:`InverseLaplaceTransform` object.
  2037. Note that this function will always assume `t` to be real,
  2038. regardless of the SymPy assumption on `t`.
  2039. For a description of possible hints, refer to the docstring of
  2040. :func:`sympy.integrals.transforms.IntegralTransform.doit`.
  2041. Examples
  2042. ========
  2043. >>> from sympy import inverse_laplace_transform, exp, Symbol
  2044. >>> from sympy.abc import s, t
  2045. >>> a = Symbol('a', positive=True)
  2046. >>> inverse_laplace_transform(exp(-a*s)/s, s, t)
  2047. Heaviside(-a + t)
  2048. See Also
  2049. ========
  2050. laplace_transform
  2051. hankel_transform, inverse_hankel_transform
  2052. """
  2053. _noconds = hints.get('noconds', True)
  2054. _simplify = hints.get('simplify', False)
  2055. if isinstance(F, MatrixBase) and hasattr(F, 'applyfunc'):
  2056. return F.applyfunc(
  2057. lambda Fij: inverse_laplace_transform(Fij, s, t, plane, **hints))
  2058. r, c = InverseLaplaceTransform(F, s, t, plane).doit(
  2059. noconds=False, simplify=_simplify)
  2060. if _noconds:
  2061. return r
  2062. else:
  2063. return r, c
  2064. def _fast_inverse_laplace(e, s, t):
  2065. """Fast inverse Laplace transform of rational function including RootSum"""
  2066. a, b, n = symbols('a, b, n', cls=Wild, exclude=[s])
  2067. def _ilt(e):
  2068. if not e.has(s):
  2069. return e
  2070. elif e.is_Add:
  2071. return _ilt_add(e)
  2072. elif e.is_Mul:
  2073. return _ilt_mul(e)
  2074. elif e.is_Pow:
  2075. return _ilt_pow(e)
  2076. elif isinstance(e, RootSum):
  2077. return _ilt_rootsum(e)
  2078. else:
  2079. raise NotImplementedError
  2080. def _ilt_add(e):
  2081. return e.func(*map(_ilt, e.args))
  2082. def _ilt_mul(e):
  2083. coeff, expr = e.as_independent(s)
  2084. if expr.is_Mul:
  2085. raise NotImplementedError
  2086. return coeff * _ilt(expr)
  2087. def _ilt_pow(e):
  2088. match = e.match((a*s + b)**n)
  2089. if match is not None:
  2090. nm, am, bm = match[n], match[a], match[b]
  2091. if nm.is_Integer and nm < 0:
  2092. return t**(-nm-1)*exp(-(bm/am)*t)/(am**-nm*gamma(-nm))
  2093. if nm == 1:
  2094. return exp(-(bm/am)*t) / am
  2095. raise NotImplementedError
  2096. def _ilt_rootsum(e):
  2097. expr = e.fun.expr
  2098. [variable] = e.fun.variables
  2099. return RootSum(e.poly, Lambda(variable, together(_ilt(expr))))
  2100. return _ilt(e)