|
""" 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 = { 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: |
|
|
|
|
|
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_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): |
|
|
|
|
|
|
|
try: |
|
ret = expr() |
|
except TypeError: |
|
ret = expr |
|
|
|
return ret |
|
|
|
|
|
def _get_state(state_class, ops, **options): |
|
|
|
|
|
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: |
|
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 |
|
|