cartesian.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. """Operators and states for 1D cartesian position and momentum.
  2. TODO:
  3. * Add 3D classes to mappings in operatorset.py
  4. """
  5. from sympy.core.numbers import (I, pi)
  6. from sympy.core.singleton import S
  7. from sympy.functions.elementary.exponential import exp
  8. from sympy.functions.elementary.miscellaneous import sqrt
  9. from sympy.functions.special.delta_functions import DiracDelta
  10. from sympy.sets.sets import Interval
  11. from sympy.physics.quantum.constants import hbar
  12. from sympy.physics.quantum.hilbert import L2
  13. from sympy.physics.quantum.operator import DifferentialOperator, HermitianOperator
  14. from sympy.physics.quantum.state import Ket, Bra, State
  15. __all__ = [
  16. 'XOp',
  17. 'YOp',
  18. 'ZOp',
  19. 'PxOp',
  20. 'X',
  21. 'Y',
  22. 'Z',
  23. 'Px',
  24. 'XKet',
  25. 'XBra',
  26. 'PxKet',
  27. 'PxBra',
  28. 'PositionState3D',
  29. 'PositionKet3D',
  30. 'PositionBra3D'
  31. ]
  32. #-------------------------------------------------------------------------
  33. # Position operators
  34. #-------------------------------------------------------------------------
  35. class XOp(HermitianOperator):
  36. """1D cartesian position operator."""
  37. @classmethod
  38. def default_args(self):
  39. return ("X",)
  40. @classmethod
  41. def _eval_hilbert_space(self, args):
  42. return L2(Interval(S.NegativeInfinity, S.Infinity))
  43. def _eval_commutator_PxOp(self, other):
  44. return I*hbar
  45. def _apply_operator_XKet(self, ket):
  46. return ket.position*ket
  47. def _apply_operator_PositionKet3D(self, ket):
  48. return ket.position_x*ket
  49. def _represent_PxKet(self, basis, *, index=1, **options):
  50. states = basis._enumerate_state(2, start_index=index)
  51. coord1 = states[0].momentum
  52. coord2 = states[1].momentum
  53. d = DifferentialOperator(coord1)
  54. delta = DiracDelta(coord1 - coord2)
  55. return I*hbar*(d*delta)
  56. class YOp(HermitianOperator):
  57. """ Y cartesian coordinate operator (for 2D or 3D systems) """
  58. @classmethod
  59. def default_args(self):
  60. return ("Y",)
  61. @classmethod
  62. def _eval_hilbert_space(self, args):
  63. return L2(Interval(S.NegativeInfinity, S.Infinity))
  64. def _apply_operator_PositionKet3D(self, ket):
  65. return ket.position_y*ket
  66. class ZOp(HermitianOperator):
  67. """ Z cartesian coordinate operator (for 3D systems) """
  68. @classmethod
  69. def default_args(self):
  70. return ("Z",)
  71. @classmethod
  72. def _eval_hilbert_space(self, args):
  73. return L2(Interval(S.NegativeInfinity, S.Infinity))
  74. def _apply_operator_PositionKet3D(self, ket):
  75. return ket.position_z*ket
  76. #-------------------------------------------------------------------------
  77. # Momentum operators
  78. #-------------------------------------------------------------------------
  79. class PxOp(HermitianOperator):
  80. """1D cartesian momentum operator."""
  81. @classmethod
  82. def default_args(self):
  83. return ("Px",)
  84. @classmethod
  85. def _eval_hilbert_space(self, args):
  86. return L2(Interval(S.NegativeInfinity, S.Infinity))
  87. def _apply_operator_PxKet(self, ket):
  88. return ket.momentum*ket
  89. def _represent_XKet(self, basis, *, index=1, **options):
  90. states = basis._enumerate_state(2, start_index=index)
  91. coord1 = states[0].position
  92. coord2 = states[1].position
  93. d = DifferentialOperator(coord1)
  94. delta = DiracDelta(coord1 - coord2)
  95. return -I*hbar*(d*delta)
  96. X = XOp('X')
  97. Y = YOp('Y')
  98. Z = ZOp('Z')
  99. Px = PxOp('Px')
  100. #-------------------------------------------------------------------------
  101. # Position eigenstates
  102. #-------------------------------------------------------------------------
  103. class XKet(Ket):
  104. """1D cartesian position eigenket."""
  105. @classmethod
  106. def _operators_to_state(self, op, **options):
  107. return self.__new__(self, *_lowercase_labels(op), **options)
  108. def _state_to_operators(self, op_class, **options):
  109. return op_class.__new__(op_class,
  110. *_uppercase_labels(self), **options)
  111. @classmethod
  112. def default_args(self):
  113. return ("x",)
  114. @classmethod
  115. def dual_class(self):
  116. return XBra
  117. @property
  118. def position(self):
  119. """The position of the state."""
  120. return self.label[0]
  121. def _enumerate_state(self, num_states, **options):
  122. return _enumerate_continuous_1D(self, num_states, **options)
  123. def _eval_innerproduct_XBra(self, bra, **hints):
  124. return DiracDelta(self.position - bra.position)
  125. def _eval_innerproduct_PxBra(self, bra, **hints):
  126. return exp(-I*self.position*bra.momentum/hbar)/sqrt(2*pi*hbar)
  127. class XBra(Bra):
  128. """1D cartesian position eigenbra."""
  129. @classmethod
  130. def default_args(self):
  131. return ("x",)
  132. @classmethod
  133. def dual_class(self):
  134. return XKet
  135. @property
  136. def position(self):
  137. """The position of the state."""
  138. return self.label[0]
  139. class PositionState3D(State):
  140. """ Base class for 3D cartesian position eigenstates """
  141. @classmethod
  142. def _operators_to_state(self, op, **options):
  143. return self.__new__(self, *_lowercase_labels(op), **options)
  144. def _state_to_operators(self, op_class, **options):
  145. return op_class.__new__(op_class,
  146. *_uppercase_labels(self), **options)
  147. @classmethod
  148. def default_args(self):
  149. return ("x", "y", "z")
  150. @property
  151. def position_x(self):
  152. """ The x coordinate of the state """
  153. return self.label[0]
  154. @property
  155. def position_y(self):
  156. """ The y coordinate of the state """
  157. return self.label[1]
  158. @property
  159. def position_z(self):
  160. """ The z coordinate of the state """
  161. return self.label[2]
  162. class PositionKet3D(Ket, PositionState3D):
  163. """ 3D cartesian position eigenket """
  164. def _eval_innerproduct_PositionBra3D(self, bra, **options):
  165. x_diff = self.position_x - bra.position_x
  166. y_diff = self.position_y - bra.position_y
  167. z_diff = self.position_z - bra.position_z
  168. return DiracDelta(x_diff)*DiracDelta(y_diff)*DiracDelta(z_diff)
  169. @classmethod
  170. def dual_class(self):
  171. return PositionBra3D
  172. # XXX: The type:ignore here is because mypy gives Definition of
  173. # "_state_to_operators" in base class "PositionState3D" is incompatible with
  174. # definition in base class "BraBase"
  175. class PositionBra3D(Bra, PositionState3D): # type: ignore
  176. """ 3D cartesian position eigenbra """
  177. @classmethod
  178. def dual_class(self):
  179. return PositionKet3D
  180. #-------------------------------------------------------------------------
  181. # Momentum eigenstates
  182. #-------------------------------------------------------------------------
  183. class PxKet(Ket):
  184. """1D cartesian momentum eigenket."""
  185. @classmethod
  186. def _operators_to_state(self, op, **options):
  187. return self.__new__(self, *_lowercase_labels(op), **options)
  188. def _state_to_operators(self, op_class, **options):
  189. return op_class.__new__(op_class,
  190. *_uppercase_labels(self), **options)
  191. @classmethod
  192. def default_args(self):
  193. return ("px",)
  194. @classmethod
  195. def dual_class(self):
  196. return PxBra
  197. @property
  198. def momentum(self):
  199. """The momentum of the state."""
  200. return self.label[0]
  201. def _enumerate_state(self, *args, **options):
  202. return _enumerate_continuous_1D(self, *args, **options)
  203. def _eval_innerproduct_XBra(self, bra, **hints):
  204. return exp(I*self.momentum*bra.position/hbar)/sqrt(2*pi*hbar)
  205. def _eval_innerproduct_PxBra(self, bra, **hints):
  206. return DiracDelta(self.momentum - bra.momentum)
  207. class PxBra(Bra):
  208. """1D cartesian momentum eigenbra."""
  209. @classmethod
  210. def default_args(self):
  211. return ("px",)
  212. @classmethod
  213. def dual_class(self):
  214. return PxKet
  215. @property
  216. def momentum(self):
  217. """The momentum of the state."""
  218. return self.label[0]
  219. #-------------------------------------------------------------------------
  220. # Global helper functions
  221. #-------------------------------------------------------------------------
  222. def _enumerate_continuous_1D(*args, **options):
  223. state = args[0]
  224. num_states = args[1]
  225. state_class = state.__class__
  226. index_list = options.pop('index_list', [])
  227. if len(index_list) == 0:
  228. start_index = options.pop('start_index', 1)
  229. index_list = list(range(start_index, start_index + num_states))
  230. enum_states = [0 for i in range(len(index_list))]
  231. for i, ind in enumerate(index_list):
  232. label = state.args[0]
  233. enum_states[i] = state_class(str(label) + "_" + str(ind), **options)
  234. return enum_states
  235. def _lowercase_labels(ops):
  236. if not isinstance(ops, set):
  237. ops = [ops]
  238. return [str(arg.label[0]).lower() for arg in ops]
  239. def _uppercase_labels(ops):
  240. if not isinstance(ops, set):
  241. ops = [ops]
  242. new_args = [str(arg.label[0])[0].upper() +
  243. str(arg.label[0])[1:] for arg in ops]
  244. return new_args