operatorset.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. """ A module for mapping operators to their corresponding eigenstates
  2. and vice versa
  3. It contains a global dictionary with eigenstate-operator pairings.
  4. If a new state-operator pair is created, this dictionary should be
  5. updated as well.
  6. It also contains functions operators_to_state and state_to_operators
  7. for mapping between the two. These can handle both classes and
  8. instances of operators and states. See the individual function
  9. descriptions for details.
  10. TODO List:
  11. - Update the dictionary with a complete list of state-operator pairs
  12. """
  13. from sympy.physics.quantum.cartesian import (XOp, YOp, ZOp, XKet, PxOp, PxKet,
  14. PositionKet3D)
  15. from sympy.physics.quantum.operator import Operator
  16. from sympy.physics.quantum.state import StateBase, BraBase, Ket
  17. from sympy.physics.quantum.spin import (JxOp, JyOp, JzOp, J2Op, JxKet, JyKet,
  18. JzKet)
  19. __all__ = [
  20. 'operators_to_state',
  21. 'state_to_operators'
  22. ]
  23. #state_mapping stores the mappings between states and their associated
  24. #operators or tuples of operators. This should be updated when new
  25. #classes are written! Entries are of the form PxKet : PxOp or
  26. #something like 3DKet : (ROp, ThetaOp, PhiOp)
  27. #frozenset is used so that the reverse mapping can be made
  28. #(regular sets are not hashable because they are mutable
  29. state_mapping = { JxKet: frozenset((J2Op, JxOp)),
  30. JyKet: frozenset((J2Op, JyOp)),
  31. JzKet: frozenset((J2Op, JzOp)),
  32. Ket: Operator,
  33. PositionKet3D: frozenset((XOp, YOp, ZOp)),
  34. PxKet: PxOp,
  35. XKet: XOp }
  36. op_mapping = {v: k for k, v in state_mapping.items()}
  37. def operators_to_state(operators, **options):
  38. """ Returns the eigenstate of the given operator or set of operators
  39. A global function for mapping operator classes to their associated
  40. states. It takes either an Operator or a set of operators and
  41. returns the state associated with these.
  42. This function can handle both instances of a given operator or
  43. just the class itself (i.e. both XOp() and XOp)
  44. There are multiple use cases to consider:
  45. 1) A class or set of classes is passed: First, we try to
  46. instantiate default instances for these operators. If this fails,
  47. then the class is simply returned. If we succeed in instantiating
  48. default instances, then we try to call state._operators_to_state
  49. on the operator instances. If this fails, the class is returned.
  50. Otherwise, the instance returned by _operators_to_state is returned.
  51. 2) An instance or set of instances is passed: In this case,
  52. state._operators_to_state is called on the instances passed. If
  53. this fails, a state class is returned. If the method returns an
  54. instance, that instance is returned.
  55. In both cases, if the operator class or set does not exist in the
  56. state_mapping dictionary, None is returned.
  57. Parameters
  58. ==========
  59. arg: Operator or set
  60. The class or instance of the operator or set of operators
  61. to be mapped to a state
  62. Examples
  63. ========
  64. >>> from sympy.physics.quantum.cartesian import XOp, PxOp
  65. >>> from sympy.physics.quantum.operatorset import operators_to_state
  66. >>> from sympy.physics.quantum.operator import Operator
  67. >>> operators_to_state(XOp)
  68. |x>
  69. >>> operators_to_state(XOp())
  70. |x>
  71. >>> operators_to_state(PxOp)
  72. |px>
  73. >>> operators_to_state(PxOp())
  74. |px>
  75. >>> operators_to_state(Operator)
  76. |psi>
  77. >>> operators_to_state(Operator())
  78. |psi>
  79. """
  80. if not (isinstance(operators, Operator)
  81. or isinstance(operators, set) or issubclass(operators, Operator)):
  82. raise NotImplementedError("Argument is not an Operator or a set!")
  83. if isinstance(operators, set):
  84. for s in operators:
  85. if not (isinstance(s, Operator)
  86. or issubclass(s, Operator)):
  87. raise NotImplementedError("Set is not all Operators!")
  88. ops = frozenset(operators)
  89. if ops in op_mapping: # ops is a list of classes in this case
  90. #Try to get an object from default instances of the
  91. #operators...if this fails, return the class
  92. try:
  93. op_instances = [op() for op in ops]
  94. ret = _get_state(op_mapping[ops], set(op_instances), **options)
  95. except NotImplementedError:
  96. ret = op_mapping[ops]
  97. return ret
  98. else:
  99. tmp = [type(o) for o in ops]
  100. classes = frozenset(tmp)
  101. if classes in op_mapping:
  102. ret = _get_state(op_mapping[classes], ops, **options)
  103. else:
  104. ret = None
  105. return ret
  106. else:
  107. if operators in op_mapping:
  108. try:
  109. op_instance = operators()
  110. ret = _get_state(op_mapping[operators], op_instance, **options)
  111. except NotImplementedError:
  112. ret = op_mapping[operators]
  113. return ret
  114. elif type(operators) in op_mapping:
  115. return _get_state(op_mapping[type(operators)], operators, **options)
  116. else:
  117. return None
  118. def state_to_operators(state, **options):
  119. """ Returns the operator or set of operators corresponding to the
  120. given eigenstate
  121. A global function for mapping state classes to their associated
  122. operators or sets of operators. It takes either a state class
  123. or instance.
  124. This function can handle both instances of a given state or just
  125. the class itself (i.e. both XKet() and XKet)
  126. There are multiple use cases to consider:
  127. 1) A state class is passed: In this case, we first try
  128. instantiating a default instance of the class. If this succeeds,
  129. then we try to call state._state_to_operators on that instance.
  130. If the creation of the default instance or if the calling of
  131. _state_to_operators fails, then either an operator class or set of
  132. operator classes is returned. Otherwise, the appropriate
  133. operator instances are returned.
  134. 2) A state instance is returned: Here, state._state_to_operators
  135. is called for the instance. If this fails, then a class or set of
  136. operator classes is returned. Otherwise, the instances are returned.
  137. In either case, if the state's class does not exist in
  138. state_mapping, None is returned.
  139. Parameters
  140. ==========
  141. arg: StateBase class or instance (or subclasses)
  142. The class or instance of the state to be mapped to an
  143. operator or set of operators
  144. Examples
  145. ========
  146. >>> from sympy.physics.quantum.cartesian import XKet, PxKet, XBra, PxBra
  147. >>> from sympy.physics.quantum.operatorset import state_to_operators
  148. >>> from sympy.physics.quantum.state import Ket, Bra
  149. >>> state_to_operators(XKet)
  150. X
  151. >>> state_to_operators(XKet())
  152. X
  153. >>> state_to_operators(PxKet)
  154. Px
  155. >>> state_to_operators(PxKet())
  156. Px
  157. >>> state_to_operators(PxBra)
  158. Px
  159. >>> state_to_operators(XBra)
  160. X
  161. >>> state_to_operators(Ket)
  162. O
  163. >>> state_to_operators(Bra)
  164. O
  165. """
  166. if not (isinstance(state, StateBase) or issubclass(state, StateBase)):
  167. raise NotImplementedError("Argument is not a state!")
  168. if state in state_mapping: # state is a class
  169. state_inst = _make_default(state)
  170. try:
  171. ret = _get_ops(state_inst,
  172. _make_set(state_mapping[state]), **options)
  173. except (NotImplementedError, TypeError):
  174. ret = state_mapping[state]
  175. elif type(state) in state_mapping:
  176. ret = _get_ops(state,
  177. _make_set(state_mapping[type(state)]), **options)
  178. elif isinstance(state, BraBase) and state.dual_class() in state_mapping:
  179. ret = _get_ops(state,
  180. _make_set(state_mapping[state.dual_class()]))
  181. elif issubclass(state, BraBase) and state.dual_class() in state_mapping:
  182. state_inst = _make_default(state)
  183. try:
  184. ret = _get_ops(state_inst,
  185. _make_set(state_mapping[state.dual_class()]))
  186. except (NotImplementedError, TypeError):
  187. ret = state_mapping[state.dual_class()]
  188. else:
  189. ret = None
  190. return _make_set(ret)
  191. def _make_default(expr):
  192. # XXX: Catching TypeError like this is a bad way of distinguishing between
  193. # classes and instances. The logic using this function should be rewritten
  194. # somehow.
  195. try:
  196. ret = expr()
  197. except TypeError:
  198. ret = expr
  199. return ret
  200. def _get_state(state_class, ops, **options):
  201. # Try to get a state instance from the operator INSTANCES.
  202. # If this fails, get the class
  203. try:
  204. ret = state_class._operators_to_state(ops, **options)
  205. except NotImplementedError:
  206. ret = _make_default(state_class)
  207. return ret
  208. def _get_ops(state_inst, op_classes, **options):
  209. # Try to get operator instances from the state INSTANCE.
  210. # If this fails, just return the classes
  211. try:
  212. ret = state_inst._state_to_operators(op_classes, **options)
  213. except NotImplementedError:
  214. if isinstance(op_classes, (set, tuple, frozenset)):
  215. ret = tuple(_make_default(x) for x in op_classes)
  216. else:
  217. ret = _make_default(op_classes)
  218. if isinstance(ret, set) and len(ret) == 1:
  219. return ret[0]
  220. return ret
  221. def _make_set(ops):
  222. if isinstance(ops, (tuple, list, frozenset)):
  223. return set(ops)
  224. else:
  225. return ops