state.py 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. """Dirac notation for states."""
  2. from sympy.core.cache import cacheit
  3. from sympy.core.containers import Tuple
  4. from sympy.core.expr import Expr
  5. from sympy.core.function import Function
  6. from sympy.core.numbers import oo
  7. from sympy.core.singleton import S
  8. from sympy.functions.elementary.complexes import conjugate
  9. from sympy.functions.elementary.miscellaneous import sqrt
  10. from sympy.integrals.integrals import integrate
  11. from sympy.printing.pretty.stringpict import stringPict
  12. from sympy.physics.quantum.qexpr import QExpr, dispatch_method
  13. __all__ = [
  14. 'KetBase',
  15. 'BraBase',
  16. 'StateBase',
  17. 'State',
  18. 'Ket',
  19. 'Bra',
  20. 'TimeDepState',
  21. 'TimeDepBra',
  22. 'TimeDepKet',
  23. 'OrthogonalKet',
  24. 'OrthogonalBra',
  25. 'OrthogonalState',
  26. 'Wavefunction'
  27. ]
  28. #-----------------------------------------------------------------------------
  29. # States, bras and kets.
  30. #-----------------------------------------------------------------------------
  31. # ASCII brackets
  32. _lbracket = "<"
  33. _rbracket = ">"
  34. _straight_bracket = "|"
  35. # Unicode brackets
  36. # MATHEMATICAL ANGLE BRACKETS
  37. _lbracket_ucode = "\N{MATHEMATICAL LEFT ANGLE BRACKET}"
  38. _rbracket_ucode = "\N{MATHEMATICAL RIGHT ANGLE BRACKET}"
  39. # LIGHT VERTICAL BAR
  40. _straight_bracket_ucode = "\N{LIGHT VERTICAL BAR}"
  41. # Other options for unicode printing of <, > and | for Dirac notation.
  42. # LEFT-POINTING ANGLE BRACKET
  43. # _lbracket = "\u2329"
  44. # _rbracket = "\u232A"
  45. # LEFT ANGLE BRACKET
  46. # _lbracket = "\u3008"
  47. # _rbracket = "\u3009"
  48. # VERTICAL LINE
  49. # _straight_bracket = "\u007C"
  50. class StateBase(QExpr):
  51. """Abstract base class for general abstract states in quantum mechanics.
  52. All other state classes defined will need to inherit from this class. It
  53. carries the basic structure for all other states such as dual, _eval_adjoint
  54. and label.
  55. This is an abstract base class and you should not instantiate it directly,
  56. instead use State.
  57. """
  58. @classmethod
  59. def _operators_to_state(self, ops, **options):
  60. """ Returns the eigenstate instance for the passed operators.
  61. This method should be overridden in subclasses. It will handle being
  62. passed either an Operator instance or set of Operator instances. It
  63. should return the corresponding state INSTANCE or simply raise a
  64. NotImplementedError. See cartesian.py for an example.
  65. """
  66. raise NotImplementedError("Cannot map operators to states in this class. Method not implemented!")
  67. def _state_to_operators(self, op_classes, **options):
  68. """ Returns the operators which this state instance is an eigenstate
  69. of.
  70. This method should be overridden in subclasses. It will be called on
  71. state instances and be passed the operator classes that we wish to make
  72. into instances. The state instance will then transform the classes
  73. appropriately, or raise a NotImplementedError if it cannot return
  74. operator instances. See cartesian.py for examples,
  75. """
  76. raise NotImplementedError(
  77. "Cannot map this state to operators. Method not implemented!")
  78. @property
  79. def operators(self):
  80. """Return the operator(s) that this state is an eigenstate of"""
  81. from .operatorset import state_to_operators # import internally to avoid circular import errors
  82. return state_to_operators(self)
  83. def _enumerate_state(self, num_states, **options):
  84. raise NotImplementedError("Cannot enumerate this state!")
  85. def _represent_default_basis(self, **options):
  86. return self._represent(basis=self.operators)
  87. #-------------------------------------------------------------------------
  88. # Dagger/dual
  89. #-------------------------------------------------------------------------
  90. @property
  91. def dual(self):
  92. """Return the dual state of this one."""
  93. return self.dual_class()._new_rawargs(self.hilbert_space, *self.args)
  94. @classmethod
  95. def dual_class(self):
  96. """Return the class used to construct the dual."""
  97. raise NotImplementedError(
  98. 'dual_class must be implemented in a subclass'
  99. )
  100. def _eval_adjoint(self):
  101. """Compute the dagger of this state using the dual."""
  102. return self.dual
  103. #-------------------------------------------------------------------------
  104. # Printing
  105. #-------------------------------------------------------------------------
  106. def _pretty_brackets(self, height, use_unicode=True):
  107. # Return pretty printed brackets for the state
  108. # Ideally, this could be done by pform.parens but it does not support the angled < and >
  109. # Setup for unicode vs ascii
  110. if use_unicode:
  111. lbracket, rbracket = getattr(self, 'lbracket_ucode', ""), getattr(self, 'rbracket_ucode', "")
  112. slash, bslash, vert = '\N{BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT}', \
  113. '\N{BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT}', \
  114. '\N{BOX DRAWINGS LIGHT VERTICAL}'
  115. else:
  116. lbracket, rbracket = getattr(self, 'lbracket', ""), getattr(self, 'rbracket', "")
  117. slash, bslash, vert = '/', '\\', '|'
  118. # If height is 1, just return brackets
  119. if height == 1:
  120. return stringPict(lbracket), stringPict(rbracket)
  121. # Make height even
  122. height += (height % 2)
  123. brackets = []
  124. for bracket in lbracket, rbracket:
  125. # Create left bracket
  126. if bracket in {_lbracket, _lbracket_ucode}:
  127. bracket_args = [ ' ' * (height//2 - i - 1) +
  128. slash for i in range(height // 2)]
  129. bracket_args.extend(
  130. [' ' * i + bslash for i in range(height // 2)])
  131. # Create right bracket
  132. elif bracket in {_rbracket, _rbracket_ucode}:
  133. bracket_args = [ ' ' * i + bslash for i in range(height // 2)]
  134. bracket_args.extend([ ' ' * (
  135. height//2 - i - 1) + slash for i in range(height // 2)])
  136. # Create straight bracket
  137. elif bracket in {_straight_bracket, _straight_bracket_ucode}:
  138. bracket_args = [vert] * height
  139. else:
  140. raise ValueError(bracket)
  141. brackets.append(
  142. stringPict('\n'.join(bracket_args), baseline=height//2))
  143. return brackets
  144. def _sympystr(self, printer, *args):
  145. contents = self._print_contents(printer, *args)
  146. return '%s%s%s' % (getattr(self, 'lbracket', ""), contents, getattr(self, 'rbracket', ""))
  147. def _pretty(self, printer, *args):
  148. from sympy.printing.pretty.stringpict import prettyForm
  149. # Get brackets
  150. pform = self._print_contents_pretty(printer, *args)
  151. lbracket, rbracket = self._pretty_brackets(
  152. pform.height(), printer._use_unicode)
  153. # Put together state
  154. pform = prettyForm(*pform.left(lbracket))
  155. pform = prettyForm(*pform.right(rbracket))
  156. return pform
  157. def _latex(self, printer, *args):
  158. contents = self._print_contents_latex(printer, *args)
  159. # The extra {} brackets are needed to get matplotlib's latex
  160. # rendered to render this properly.
  161. return '{%s%s%s}' % (getattr(self, 'lbracket_latex', ""), contents, getattr(self, 'rbracket_latex', ""))
  162. class KetBase(StateBase):
  163. """Base class for Kets.
  164. This class defines the dual property and the brackets for printing. This is
  165. an abstract base class and you should not instantiate it directly, instead
  166. use Ket.
  167. """
  168. lbracket = _straight_bracket
  169. rbracket = _rbracket
  170. lbracket_ucode = _straight_bracket_ucode
  171. rbracket_ucode = _rbracket_ucode
  172. lbracket_latex = r'\left|'
  173. rbracket_latex = r'\right\rangle '
  174. @classmethod
  175. def default_args(self):
  176. return ("psi",)
  177. @classmethod
  178. def dual_class(self):
  179. return BraBase
  180. def __mul__(self, other):
  181. """KetBase*other"""
  182. from sympy.physics.quantum.operator import OuterProduct
  183. if isinstance(other, BraBase):
  184. return OuterProduct(self, other)
  185. else:
  186. return Expr.__mul__(self, other)
  187. def __rmul__(self, other):
  188. """other*KetBase"""
  189. from sympy.physics.quantum.innerproduct import InnerProduct
  190. if isinstance(other, BraBase):
  191. return InnerProduct(other, self)
  192. else:
  193. return Expr.__rmul__(self, other)
  194. #-------------------------------------------------------------------------
  195. # _eval_* methods
  196. #-------------------------------------------------------------------------
  197. def _eval_innerproduct(self, bra, **hints):
  198. """Evaluate the inner product between this ket and a bra.
  199. This is called to compute <bra|ket>, where the ket is ``self``.
  200. This method will dispatch to sub-methods having the format::
  201. ``def _eval_innerproduct_BraClass(self, **hints):``
  202. Subclasses should define these methods (one for each BraClass) to
  203. teach the ket how to take inner products with bras.
  204. """
  205. return dispatch_method(self, '_eval_innerproduct', bra, **hints)
  206. def _apply_operator(self, op, **options):
  207. """Apply an Operator to this Ket.
  208. This method will dispatch to methods having the format::
  209. ``def _apply_operator_OperatorName(op, **options):``
  210. Subclasses should define these methods (one for each OperatorName) to
  211. teach the Ket how operators act on it.
  212. Parameters
  213. ==========
  214. op : Operator
  215. The Operator that is acting on the Ket.
  216. options : dict
  217. A dict of key/value pairs that control how the operator is applied
  218. to the Ket.
  219. """
  220. return dispatch_method(self, '_apply_operator', op, **options)
  221. class BraBase(StateBase):
  222. """Base class for Bras.
  223. This class defines the dual property and the brackets for printing. This
  224. is an abstract base class and you should not instantiate it directly,
  225. instead use Bra.
  226. """
  227. lbracket = _lbracket
  228. rbracket = _straight_bracket
  229. lbracket_ucode = _lbracket_ucode
  230. rbracket_ucode = _straight_bracket_ucode
  231. lbracket_latex = r'\left\langle '
  232. rbracket_latex = r'\right|'
  233. @classmethod
  234. def _operators_to_state(self, ops, **options):
  235. state = self.dual_class()._operators_to_state(ops, **options)
  236. return state.dual
  237. def _state_to_operators(self, op_classes, **options):
  238. return self.dual._state_to_operators(op_classes, **options)
  239. def _enumerate_state(self, num_states, **options):
  240. dual_states = self.dual._enumerate_state(num_states, **options)
  241. return [x.dual for x in dual_states]
  242. @classmethod
  243. def default_args(self):
  244. return self.dual_class().default_args()
  245. @classmethod
  246. def dual_class(self):
  247. return KetBase
  248. def __mul__(self, other):
  249. """BraBase*other"""
  250. from sympy.physics.quantum.innerproduct import InnerProduct
  251. if isinstance(other, KetBase):
  252. return InnerProduct(self, other)
  253. else:
  254. return Expr.__mul__(self, other)
  255. def __rmul__(self, other):
  256. """other*BraBase"""
  257. from sympy.physics.quantum.operator import OuterProduct
  258. if isinstance(other, KetBase):
  259. return OuterProduct(other, self)
  260. else:
  261. return Expr.__rmul__(self, other)
  262. def _represent(self, **options):
  263. """A default represent that uses the Ket's version."""
  264. from sympy.physics.quantum.dagger import Dagger
  265. return Dagger(self.dual._represent(**options))
  266. class State(StateBase):
  267. """General abstract quantum state used as a base class for Ket and Bra."""
  268. pass
  269. class Ket(State, KetBase):
  270. """A general time-independent Ket in quantum mechanics.
  271. Inherits from State and KetBase. This class should be used as the base
  272. class for all physical, time-independent Kets in a system. This class
  273. and its subclasses will be the main classes that users will use for
  274. expressing Kets in Dirac notation [1]_.
  275. Parameters
  276. ==========
  277. args : tuple
  278. The list of numbers or parameters that uniquely specify the
  279. ket. This will usually be its symbol or its quantum numbers. For
  280. time-dependent state, this will include the time.
  281. Examples
  282. ========
  283. Create a simple Ket and looking at its properties::
  284. >>> from sympy.physics.quantum import Ket
  285. >>> from sympy import symbols, I
  286. >>> k = Ket('psi')
  287. >>> k
  288. |psi>
  289. >>> k.hilbert_space
  290. H
  291. >>> k.is_commutative
  292. False
  293. >>> k.label
  294. (psi,)
  295. Ket's know about their associated bra::
  296. >>> k.dual
  297. <psi|
  298. >>> k.dual_class()
  299. <class 'sympy.physics.quantum.state.Bra'>
  300. Take a linear combination of two kets::
  301. >>> k0 = Ket(0)
  302. >>> k1 = Ket(1)
  303. >>> 2*I*k0 - 4*k1
  304. 2*I*|0> - 4*|1>
  305. Compound labels are passed as tuples::
  306. >>> n, m = symbols('n,m')
  307. >>> k = Ket(n,m)
  308. >>> k
  309. |nm>
  310. References
  311. ==========
  312. .. [1] https://en.wikipedia.org/wiki/Bra-ket_notation
  313. """
  314. @classmethod
  315. def dual_class(self):
  316. return Bra
  317. class Bra(State, BraBase):
  318. """A general time-independent Bra in quantum mechanics.
  319. Inherits from State and BraBase. A Bra is the dual of a Ket [1]_. This
  320. class and its subclasses will be the main classes that users will use for
  321. expressing Bras in Dirac notation.
  322. Parameters
  323. ==========
  324. args : tuple
  325. The list of numbers or parameters that uniquely specify the
  326. ket. This will usually be its symbol or its quantum numbers. For
  327. time-dependent state, this will include the time.
  328. Examples
  329. ========
  330. Create a simple Bra and look at its properties::
  331. >>> from sympy.physics.quantum import Bra
  332. >>> from sympy import symbols, I
  333. >>> b = Bra('psi')
  334. >>> b
  335. <psi|
  336. >>> b.hilbert_space
  337. H
  338. >>> b.is_commutative
  339. False
  340. Bra's know about their dual Ket's::
  341. >>> b.dual
  342. |psi>
  343. >>> b.dual_class()
  344. <class 'sympy.physics.quantum.state.Ket'>
  345. Like Kets, Bras can have compound labels and be manipulated in a similar
  346. manner::
  347. >>> n, m = symbols('n,m')
  348. >>> b = Bra(n,m) - I*Bra(m,n)
  349. >>> b
  350. -I*<mn| + <nm|
  351. Symbols in a Bra can be substituted using ``.subs``::
  352. >>> b.subs(n,m)
  353. <mm| - I*<mm|
  354. References
  355. ==========
  356. .. [1] https://en.wikipedia.org/wiki/Bra-ket_notation
  357. """
  358. @classmethod
  359. def dual_class(self):
  360. return Ket
  361. #-----------------------------------------------------------------------------
  362. # Time dependent states, bras and kets.
  363. #-----------------------------------------------------------------------------
  364. class TimeDepState(StateBase):
  365. """Base class for a general time-dependent quantum state.
  366. This class is used as a base class for any time-dependent state. The main
  367. difference between this class and the time-independent state is that this
  368. class takes a second argument that is the time in addition to the usual
  369. label argument.
  370. Parameters
  371. ==========
  372. args : tuple
  373. The list of numbers or parameters that uniquely specify the ket. This
  374. will usually be its symbol or its quantum numbers. For time-dependent
  375. state, this will include the time as the final argument.
  376. """
  377. #-------------------------------------------------------------------------
  378. # Initialization
  379. #-------------------------------------------------------------------------
  380. @classmethod
  381. def default_args(self):
  382. return ("psi", "t")
  383. #-------------------------------------------------------------------------
  384. # Properties
  385. #-------------------------------------------------------------------------
  386. @property
  387. def label(self):
  388. """The label of the state."""
  389. return self.args[:-1]
  390. @property
  391. def time(self):
  392. """The time of the state."""
  393. return self.args[-1]
  394. #-------------------------------------------------------------------------
  395. # Printing
  396. #-------------------------------------------------------------------------
  397. def _print_time(self, printer, *args):
  398. return printer._print(self.time, *args)
  399. _print_time_repr = _print_time
  400. _print_time_latex = _print_time
  401. def _print_time_pretty(self, printer, *args):
  402. pform = printer._print(self.time, *args)
  403. return pform
  404. def _print_contents(self, printer, *args):
  405. label = self._print_label(printer, *args)
  406. time = self._print_time(printer, *args)
  407. return '%s;%s' % (label, time)
  408. def _print_label_repr(self, printer, *args):
  409. label = self._print_sequence(self.label, ',', printer, *args)
  410. time = self._print_time_repr(printer, *args)
  411. return '%s,%s' % (label, time)
  412. def _print_contents_pretty(self, printer, *args):
  413. label = self._print_label_pretty(printer, *args)
  414. time = self._print_time_pretty(printer, *args)
  415. return printer._print_seq((label, time), delimiter=';')
  416. def _print_contents_latex(self, printer, *args):
  417. label = self._print_sequence(
  418. self.label, self._label_separator, printer, *args)
  419. time = self._print_time_latex(printer, *args)
  420. return '%s;%s' % (label, time)
  421. class TimeDepKet(TimeDepState, KetBase):
  422. """General time-dependent Ket in quantum mechanics.
  423. This inherits from ``TimeDepState`` and ``KetBase`` and is the main class
  424. that should be used for Kets that vary with time. Its dual is a
  425. ``TimeDepBra``.
  426. Parameters
  427. ==========
  428. args : tuple
  429. The list of numbers or parameters that uniquely specify the ket. This
  430. will usually be its symbol or its quantum numbers. For time-dependent
  431. state, this will include the time as the final argument.
  432. Examples
  433. ========
  434. Create a TimeDepKet and look at its attributes::
  435. >>> from sympy.physics.quantum import TimeDepKet
  436. >>> k = TimeDepKet('psi', 't')
  437. >>> k
  438. |psi;t>
  439. >>> k.time
  440. t
  441. >>> k.label
  442. (psi,)
  443. >>> k.hilbert_space
  444. H
  445. TimeDepKets know about their dual bra::
  446. >>> k.dual
  447. <psi;t|
  448. >>> k.dual_class()
  449. <class 'sympy.physics.quantum.state.TimeDepBra'>
  450. """
  451. @classmethod
  452. def dual_class(self):
  453. return TimeDepBra
  454. class TimeDepBra(TimeDepState, BraBase):
  455. """General time-dependent Bra in quantum mechanics.
  456. This inherits from TimeDepState and BraBase and is the main class that
  457. should be used for Bras that vary with time. Its dual is a TimeDepBra.
  458. Parameters
  459. ==========
  460. args : tuple
  461. The list of numbers or parameters that uniquely specify the ket. This
  462. will usually be its symbol or its quantum numbers. For time-dependent
  463. state, this will include the time as the final argument.
  464. Examples
  465. ========
  466. >>> from sympy.physics.quantum import TimeDepBra
  467. >>> b = TimeDepBra('psi', 't')
  468. >>> b
  469. <psi;t|
  470. >>> b.time
  471. t
  472. >>> b.label
  473. (psi,)
  474. >>> b.hilbert_space
  475. H
  476. >>> b.dual
  477. |psi;t>
  478. """
  479. @classmethod
  480. def dual_class(self):
  481. return TimeDepKet
  482. class OrthogonalState(State, StateBase):
  483. """General abstract quantum state used as a base class for Ket and Bra."""
  484. pass
  485. class OrthogonalKet(OrthogonalState, KetBase):
  486. """Orthogonal Ket in quantum mechanics.
  487. The inner product of two states with different labels will give zero,
  488. states with the same label will give one.
  489. >>> from sympy.physics.quantum import OrthogonalBra, OrthogonalKet
  490. >>> from sympy.abc import m, n
  491. >>> (OrthogonalBra(n)*OrthogonalKet(n)).doit()
  492. 1
  493. >>> (OrthogonalBra(n)*OrthogonalKet(n+1)).doit()
  494. 0
  495. >>> (OrthogonalBra(n)*OrthogonalKet(m)).doit()
  496. <n|m>
  497. """
  498. @classmethod
  499. def dual_class(self):
  500. return OrthogonalBra
  501. def _eval_innerproduct(self, bra, **hints):
  502. if len(self.args) != len(bra.args):
  503. raise ValueError('Cannot multiply a ket that has a different number of labels.')
  504. for i in range(len(self.args)):
  505. diff = self.args[i] - bra.args[i]
  506. diff = diff.expand()
  507. if diff.is_zero is False:
  508. return 0
  509. if diff.is_zero is None:
  510. return None
  511. return 1
  512. class OrthogonalBra(OrthogonalState, BraBase):
  513. """Orthogonal Bra in quantum mechanics.
  514. """
  515. @classmethod
  516. def dual_class(self):
  517. return OrthogonalKet
  518. class Wavefunction(Function):
  519. """Class for representations in continuous bases
  520. This class takes an expression and coordinates in its constructor. It can
  521. be used to easily calculate normalizations and probabilities.
  522. Parameters
  523. ==========
  524. expr : Expr
  525. The expression representing the functional form of the w.f.
  526. coords : Symbol or tuple
  527. The coordinates to be integrated over, and their bounds
  528. Examples
  529. ========
  530. Particle in a box, specifying bounds in the more primitive way of using
  531. Piecewise:
  532. >>> from sympy import Symbol, Piecewise, pi, N
  533. >>> from sympy.functions import sqrt, sin
  534. >>> from sympy.physics.quantum.state import Wavefunction
  535. >>> x = Symbol('x', real=True)
  536. >>> n = 1
  537. >>> L = 1
  538. >>> g = Piecewise((0, x < 0), (0, x > L), (sqrt(2//L)*sin(n*pi*x/L), True))
  539. >>> f = Wavefunction(g, x)
  540. >>> f.norm
  541. 1
  542. >>> f.is_normalized
  543. True
  544. >>> p = f.prob()
  545. >>> p(0)
  546. 0
  547. >>> p(L)
  548. 0
  549. >>> p(0.5)
  550. 2
  551. >>> p(0.85*L)
  552. 2*sin(0.85*pi)**2
  553. >>> N(p(0.85*L))
  554. 0.412214747707527
  555. Additionally, you can specify the bounds of the function and the indices in
  556. a more compact way:
  557. >>> from sympy import symbols, pi, diff
  558. >>> from sympy.functions import sqrt, sin
  559. >>> from sympy.physics.quantum.state import Wavefunction
  560. >>> x, L = symbols('x,L', positive=True)
  561. >>> n = symbols('n', integer=True, positive=True)
  562. >>> g = sqrt(2/L)*sin(n*pi*x/L)
  563. >>> f = Wavefunction(g, (x, 0, L))
  564. >>> f.norm
  565. 1
  566. >>> f(L+1)
  567. 0
  568. >>> f(L-1)
  569. sqrt(2)*sin(pi*n*(L - 1)/L)/sqrt(L)
  570. >>> f(-1)
  571. 0
  572. >>> f(0.85)
  573. sqrt(2)*sin(0.85*pi*n/L)/sqrt(L)
  574. >>> f(0.85, n=1, L=1)
  575. sqrt(2)*sin(0.85*pi)
  576. >>> f.is_commutative
  577. False
  578. All arguments are automatically sympified, so you can define the variables
  579. as strings rather than symbols:
  580. >>> expr = x**2
  581. >>> f = Wavefunction(expr, 'x')
  582. >>> type(f.variables[0])
  583. <class 'sympy.core.symbol.Symbol'>
  584. Derivatives of Wavefunctions will return Wavefunctions:
  585. >>> diff(f, x)
  586. Wavefunction(2*x, x)
  587. """
  588. #Any passed tuples for coordinates and their bounds need to be
  589. #converted to Tuples before Function's constructor is called, to
  590. #avoid errors from calling is_Float in the constructor
  591. def __new__(cls, *args, **options):
  592. new_args = [None for i in args]
  593. ct = 0
  594. for arg in args:
  595. if isinstance(arg, tuple):
  596. new_args[ct] = Tuple(*arg)
  597. else:
  598. new_args[ct] = arg
  599. ct += 1
  600. return super().__new__(cls, *new_args, **options)
  601. def __call__(self, *args, **options):
  602. var = self.variables
  603. if len(args) != len(var):
  604. raise NotImplementedError(
  605. "Incorrect number of arguments to function!")
  606. ct = 0
  607. #If the passed value is outside the specified bounds, return 0
  608. for v in var:
  609. lower, upper = self.limits[v]
  610. #Do the comparison to limits only if the passed symbol is actually
  611. #a symbol present in the limits;
  612. #Had problems with a comparison of x > L
  613. if isinstance(args[ct], Expr) and \
  614. not (lower in args[ct].free_symbols
  615. or upper in args[ct].free_symbols):
  616. continue
  617. if (args[ct] < lower) == True or (args[ct] > upper) == True:
  618. return S.Zero
  619. ct += 1
  620. expr = self.expr
  621. #Allows user to make a call like f(2, 4, m=1, n=1)
  622. for symbol in list(expr.free_symbols):
  623. if str(symbol) in options.keys():
  624. val = options[str(symbol)]
  625. expr = expr.subs(symbol, val)
  626. return expr.subs(zip(var, args))
  627. def _eval_derivative(self, symbol):
  628. expr = self.expr
  629. deriv = expr._eval_derivative(symbol)
  630. return Wavefunction(deriv, *self.args[1:])
  631. def _eval_conjugate(self):
  632. return Wavefunction(conjugate(self.expr), *self.args[1:])
  633. def _eval_transpose(self):
  634. return self
  635. @property
  636. def free_symbols(self):
  637. return self.expr.free_symbols
  638. @property
  639. def is_commutative(self):
  640. """
  641. Override Function's is_commutative so that order is preserved in
  642. represented expressions
  643. """
  644. return False
  645. @classmethod
  646. def eval(self, *args):
  647. return None
  648. @property
  649. def variables(self):
  650. """
  651. Return the coordinates which the wavefunction depends on
  652. Examples
  653. ========
  654. >>> from sympy.physics.quantum.state import Wavefunction
  655. >>> from sympy import symbols
  656. >>> x,y = symbols('x,y')
  657. >>> f = Wavefunction(x*y, x, y)
  658. >>> f.variables
  659. (x, y)
  660. >>> g = Wavefunction(x*y, x)
  661. >>> g.variables
  662. (x,)
  663. """
  664. var = [g[0] if isinstance(g, Tuple) else g for g in self._args[1:]]
  665. return tuple(var)
  666. @property
  667. def limits(self):
  668. """
  669. Return the limits of the coordinates which the w.f. depends on If no
  670. limits are specified, defaults to ``(-oo, oo)``.
  671. Examples
  672. ========
  673. >>> from sympy.physics.quantum.state import Wavefunction
  674. >>> from sympy import symbols
  675. >>> x, y = symbols('x, y')
  676. >>> f = Wavefunction(x**2, (x, 0, 1))
  677. >>> f.limits
  678. {x: (0, 1)}
  679. >>> f = Wavefunction(x**2, x)
  680. >>> f.limits
  681. {x: (-oo, oo)}
  682. >>> f = Wavefunction(x**2 + y**2, x, (y, -1, 2))
  683. >>> f.limits
  684. {x: (-oo, oo), y: (-1, 2)}
  685. """
  686. limits = [(g[1], g[2]) if isinstance(g, Tuple) else (-oo, oo)
  687. for g in self._args[1:]]
  688. return dict(zip(self.variables, tuple(limits)))
  689. @property
  690. def expr(self):
  691. """
  692. Return the expression which is the functional form of the Wavefunction
  693. Examples
  694. ========
  695. >>> from sympy.physics.quantum.state import Wavefunction
  696. >>> from sympy import symbols
  697. >>> x, y = symbols('x, y')
  698. >>> f = Wavefunction(x**2, x)
  699. >>> f.expr
  700. x**2
  701. """
  702. return self._args[0]
  703. @property
  704. def is_normalized(self):
  705. """
  706. Returns true if the Wavefunction is properly normalized
  707. Examples
  708. ========
  709. >>> from sympy import symbols, pi
  710. >>> from sympy.functions import sqrt, sin
  711. >>> from sympy.physics.quantum.state import Wavefunction
  712. >>> x, L = symbols('x,L', positive=True)
  713. >>> n = symbols('n', integer=True, positive=True)
  714. >>> g = sqrt(2/L)*sin(n*pi*x/L)
  715. >>> f = Wavefunction(g, (x, 0, L))
  716. >>> f.is_normalized
  717. True
  718. """
  719. return (self.norm == 1.0)
  720. @property # type: ignore
  721. @cacheit
  722. def norm(self):
  723. """
  724. Return the normalization of the specified functional form.
  725. This function integrates over the coordinates of the Wavefunction, with
  726. the bounds specified.
  727. Examples
  728. ========
  729. >>> from sympy import symbols, pi
  730. >>> from sympy.functions import sqrt, sin
  731. >>> from sympy.physics.quantum.state import Wavefunction
  732. >>> x, L = symbols('x,L', positive=True)
  733. >>> n = symbols('n', integer=True, positive=True)
  734. >>> g = sqrt(2/L)*sin(n*pi*x/L)
  735. >>> f = Wavefunction(g, (x, 0, L))
  736. >>> f.norm
  737. 1
  738. >>> g = sin(n*pi*x/L)
  739. >>> f = Wavefunction(g, (x, 0, L))
  740. >>> f.norm
  741. sqrt(2)*sqrt(L)/2
  742. """
  743. exp = self.expr*conjugate(self.expr)
  744. var = self.variables
  745. limits = self.limits
  746. for v in var:
  747. curr_limits = limits[v]
  748. exp = integrate(exp, (v, curr_limits[0], curr_limits[1]))
  749. return sqrt(exp)
  750. def normalize(self):
  751. """
  752. Return a normalized version of the Wavefunction
  753. Examples
  754. ========
  755. >>> from sympy import symbols, pi
  756. >>> from sympy.functions import sin
  757. >>> from sympy.physics.quantum.state import Wavefunction
  758. >>> x = symbols('x', real=True)
  759. >>> L = symbols('L', positive=True)
  760. >>> n = symbols('n', integer=True, positive=True)
  761. >>> g = sin(n*pi*x/L)
  762. >>> f = Wavefunction(g, (x, 0, L))
  763. >>> f.normalize()
  764. Wavefunction(sqrt(2)*sin(pi*n*x/L)/sqrt(L), (x, 0, L))
  765. """
  766. const = self.norm
  767. if const is oo:
  768. raise NotImplementedError("The function is not normalizable!")
  769. else:
  770. return Wavefunction((const)**(-1)*self.expr, *self.args[1:])
  771. def prob(self):
  772. r"""
  773. Return the absolute magnitude of the w.f., `|\psi(x)|^2`
  774. Examples
  775. ========
  776. >>> from sympy import symbols, pi
  777. >>> from sympy.functions import sin
  778. >>> from sympy.physics.quantum.state import Wavefunction
  779. >>> x, L = symbols('x,L', real=True)
  780. >>> n = symbols('n', integer=True)
  781. >>> g = sin(n*pi*x/L)
  782. >>> f = Wavefunction(g, (x, 0, L))
  783. >>> f.prob()
  784. Wavefunction(sin(pi*n*x/L)**2, x)
  785. """
  786. return Wavefunction(self.expr*conjugate(self.expr), *self.variables)