state.py 29 KB

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