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