# Quantum Angular Momentum Module

This file will show how to use the various objects and methods in the sympy.physics.quantum.spin module, with some examples. Much of the work in this module is based off Varschalovich "Quantum Theory of Angular Momentum".



In :

from sympy.physics.quantum.spin import Jminus, Jx, Jz, J2, J2Op, JzKet, JzKetCoupled, Rotation, WignerD, couple, uncouple
from sympy.physics.quantum import Dagger, hbar, qapply, represent, TensorProduct
from sympy import factor, pi, S, Sum, symbols



## Basic spin states and operators

We can define simple spin states and operators and manipulate them with standard quantum machinery.

Define a spin ket:



In :

jz = JzKet(1,1); jz




Out:

$${\left|1,1\right\rangle }$$



Find the vector representation of the state:



In :

represent(jz)




Out:

$$\left[\begin{smallmatrix}1\\0\\0\end{smallmatrix}\right]$$



Create and evaluate an innerproduct of a bra and a ket:



In :

ip = Dagger(jz) * jz; ip




Out:

$$\left\langle 1,1 \right. {\left|1,1\right\rangle }$$




In :

ip.doit()




Out:

$$1$$



Apply an angular momentum operator to the state:



In :

Jz * jz




Out:

$$J_z {\left|1,1\right\rangle }$$




In :

qapply(Jz * jz)




Out:

$$\hbar {\left|1,1\right\rangle }$$




In :

Jminus * jz




Out:

$$J_- {\left|1,1\right\rangle }$$




In :

qapply(Jminus * jz)




Out:

$$\sqrt{2} \hbar {\left|1,0\right\rangle }$$



We can also do this for symbolic angular momentum states:



In :

j, m = symbols('j m')
jz = JzKet(j, m); jz




Out:

$${\left|j,m\right\rangle }$$




In :

J2 * jz




Out:

$$J^2 {\left|j,m\right\rangle }$$




In :

qapply(J2 * jz)




Out:

$$\hbar^{2} j^{2} {\left|j,m\right\rangle } + \hbar^{2} j {\left|j,m\right\rangle }$$



Find the matrix representation of a angular momentum operator:



In :

represent(Jz, j=1)




Out:

$$\left[\begin{smallmatrix}\hbar & 0 & 0\\0 & 0 & 0\\0 & 0 & - \hbar\end{smallmatrix}\right]$$



## Utilizing different bases

Angular momentum states and operators are able to go between different spin bases

We can rewrite states as states in another basis:



In :

jz = JzKet(1, 1)
jz.rewrite("Jx")




Out:

$$\frac{1}{2} {\left|1,-1\right\rangle } - \frac{1}{2} \sqrt{2} {\left|1,0\right\rangle } + \frac{1}{2} {\left|1,1\right\rangle }$$



Vector representation can also be done into different bases:



In :

represent(jz, basis=Jx)




Out:

$$\left[\begin{smallmatrix}\frac{1}{2}\\- \frac{1}{2} \sqrt{2}\\\frac{1}{2}\end{smallmatrix}\right]$$



When applying operators in another spin basis, any conversion necessary to apply the state is done, then the states are given back in the original basis. So in the following example, the state returned by qapply are in the $J_z$ basis:



In :

Jx * jz




Out:

$$J_x {\left|1,1\right\rangle }$$




In :

qapply(Jx * jz)




Out:

$$\frac{1}{2} \sqrt{2} \hbar {\left|1,0\right\rangle }$$



Rewriting states and applying operators between bases can also be done symbolically. In this case, the result is given in terms of Wigner-D matrix elements (see the next section for more information on the Rotation operator).



In :

jz = JzKet(j, m)
jz.rewrite("Jx")




Out:

$$\sum_{mi=- j}^{j} d^{j}_{mi,m}\left(\frac{3}{2} \pi\right) {\left|j,mi\right\rangle }$$



## Rotation Operator

Arbitrary rotations of spin states, written in terms of Euler angles, can be modeled using the rotation operator. These methods are utilized to go between spin bases, as seen in the section above.

Define an arbitrary rotation operator. The given angles are Euler angles in the z-y-z convention.



In :

a, b, g = symbols('alpha beta gamma')
Rotation(a, b, g)




Out:

$$\mathcal{R}\left(\alpha,\beta,\gamma\right)$$



Find the Wigner-D matrix elements of the rotation operator as given by $\langle j, m'|\mathcal{R}(\alpha, \beta, \gamma)|j,m\rangle$:



In :

mp = symbols('mp')
r = Rotation.D(j, m, mp, a, b, g); r




Out:

$$D^{j}_{m,mp}\left(\alpha,\beta,\gamma\right)$$



Numerical matrix elements can be evaluated using the .doit() method:



In :

r = Rotation.D(1, 1, 0, pi, pi/2, 0); r




Out:

$$D^{1}_{1,0}\left(\pi,\frac{1}{2} \pi,0\right)$$




In :

r.doit()




Out:

$$\frac{1}{2} \sqrt{2}$$



The Wigner small-d matrix elements give rotations when $\alpha=\gamma=0$. These matrix elements can be found in the same manner as above:



In :

r = Rotation.d(j, m, mp, b); r




Out:

$$d^{j}_{m,mp}\left(\beta\right)$$




In :

r = Rotation.d(1, 1, 0, pi/2); r




Out:

$$d^{1}_{1,0}\left(\frac{1}{2} \pi\right)$$




In :

r.doit()




Out:

$$- \frac{1}{2} \sqrt{2}$$



You can also directly create a Wigner-D matrix element:



In :

WignerD(j, m, mp, a, b, g)




Out:

$$D^{j}_{m,mp}\left(\alpha,\beta,\gamma\right)$$



## Coupled and Uncoupled States and Operators

States and operators can also written in terms of coupled or uncoupled angular momentum spaces.

### Coupled States and Operators

Define a simple coupled state of two $j=1$ spin states:



In :

jzc = JzKetCoupled(1, 0, (1, 1)); jzc




Out:

$${\left|1,0,j_{1}=1,j_{2}=1\right\rangle }$$



Note that the Hilbert space of coupled states is the direct sum of the coupled spin spaces. This can be seen in the matrix representation of coupled states:



In :

jzc.hilbert_space




Out:

$$\mathcal{C}^{5}\oplus \mathcal{C}^{3}\oplus \mathcal{C}^{1}$$




In :

represent(jzc)




Out:

$$\left[\begin{smallmatrix}0\\0\\1\\0\\0\\0\\0\\0\\0\end{smallmatrix}\right]$$



We can also couple more than two spaces together. See the JzKetCoupled documentation for more complex coupling schemes involving more than 2 spaces.



In :

jzc = JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1)); jzc




Out:

$${\left|1,1,j_{1}=\frac{1}{2},j_{2}=\frac{1}{2},j_{3}=1,j_{1,2}=1\right\rangle }$$



The normal operators are assumed to be diagonal in the corresponding coupled basis:



In :

qapply(Jz * jzc)




Out:

$$\hbar {\left|1,1,j_{1}=\frac{1}{2},j_{2}=\frac{1}{2},j_{3}=1,j_{1,2}=1\right\rangle }$$



### Uncoupled States and Operators

Uncoupled states are defined as tensor products of states:



In :

jzu = TensorProduct(JzKet(1, 1), JzKet(S(1)/2, -S(1)/2)); jzu




Out:

$${{\left|1,1\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }}$$



Vector representation of tensor product states gives the vector in the direct product space:



In :

represent(jzu)




Out:

$$\left[\begin{smallmatrix}0\\1\\0\\0\\0\\0\end{smallmatrix}\right]$$



Uncoupled operators are also defined as tensor products:



In :

jzopu = TensorProduct(Jz, 1); jzopu




Out:

$${J_z}\otimes {1}$$




In :

qapply(jzopu * jzu)




Out:

$$\hbar {{\left|1,1\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }}$$



Coupled operators which are diagonalized by uncoupled states (e.g. $J_z$ and uncoupled $J_z$ eigenstates) can also be applied:



In :

qapply(Jz * jzu)




Out:

$$\frac{1}{2} \hbar {{\left|1,1\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }}$$



Rewriting states works as before:



In :

jzu.rewrite("Jx")




Out:

$$- \frac{1}{4} \sqrt{2} {{\left|1,-1\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }} - \frac{1}{4} \sqrt{2} {{\left|1,-1\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }} + \frac{1}{2} {{\left|1,0\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }} + \frac{1}{2} {{\left|1,0\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }} - \frac{1}{4} \sqrt{2} {{\left|1,1\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }} - \frac{1}{4} \sqrt{2} {{\left|1,1\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }}$$



### Coulping and Uncoupling States

The couple method will couple an uncoupled state:



In :

jzu = TensorProduct(JzKet(1, 1), JzKet(S(1)/2, -S(1)/2))
couple(jzu)




Out:

$$\frac{1}{3} \sqrt{6} {\left|\frac{1}{2},\frac{1}{2},j_{1}=1,j_{2}=\frac{1}{2}\right\rangle } + \frac{1}{3} \sqrt{3} {\left|\frac{3}{2},\frac{1}{2},j_{1}=1,j_{2}=\frac{1}{2}\right\rangle }$$



Similarly, the uncouple method will uncouple a coupled state



In :

jzc = JzKetCoupled(2, 1, (1, S(1)/2, S(1)/2))
uncouple(jzc)




Out:

$$\frac{1}{2} \sqrt{2} {{\left|1,0\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }} + \frac{1}{2} {{\left|1,1\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }} + \frac{1}{2} {{\left|1,1\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }}$$



Uncoupling can also be done with the .rewrite method:



In :

jzc.rewrite("Jz", coupled=False)




Out:

$$\frac{1}{2} \sqrt{2} {{\left|1,0\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }} + \frac{1}{2} {{\left|1,1\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }} + \frac{1}{2} {{\left|1,1\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }}$$



The uncouple method can also uncouple normal states if given a set of spin bases to consider:



In :

jz = JzKet(2, 1)
uncouple(jz, (1, S(1)/2, S(1)/2))




Out:

$$\frac{1}{2} \sqrt{2} {{\left|1,0\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }} + \frac{1}{2} {{\left|1,1\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }} + \frac{1}{2} {{\left|1,1\right\rangle }}\otimes {{\left|\frac{1}{2},\frac{1}{2}\right\rangle }}\otimes {{\left|\frac{1}{2},- \frac{1}{2}\right\rangle }}$$



## Example: Spin-orbit Coupling

If we start with a hydrogen atom, i.e. a nucleus of charge $Ze$ orbited by a single electron of charge $e$ with reduced mass $\mu$, ignoring energy from center-of-mass motion, we can write the Hamiltonian in terms of the relative momentum, $p$, and position, $r$, as:

$$H=\frac{p^2}{2\mu} - \frac{Ze^2}{r}$$

The resulting eigenfunctions have a seperate radial and angular compents, $\psi=R_{n,l}(r)Y_{l,m}(\phi,\theta)$. While the radial component is a complicated function involving Laguere polynomials, the radial part is the familiar spherical harmonics with orbital angular momentum $\vec{L}$, where $l$ and $m$ give the orbital angular momentum quantum numbers. We represent this as a angular momentum state:



In :

l, ml = symbols('l m_l')
orbit = JzKet(l, ml); orbit




Out:

$${\left|l,m_{l}\right\rangle }$$



Now, the spin orbit interaction arises from the electron experiencing a magnetic field as it orbits the electrically charged nucleus. This magnetic field is:

$$\vec{B} = \frac{1}{c}\frac{Ze\vec{v}\times\vec{r}}{r^3} = \frac{Ze\vec{p}\times\vec{r}}{mcr^3}=\frac{Ze\vec{L}}{mc\hbar r^3}$$

Then the spin-orbit Hamiltonian can be written, using the electron's magnetic dipole moment $\mu$, as:

$$H_{SO} = -\vec{\mu}\cdot\vec{B} = -\left(-\frac{g\mu_B \vec{S}}{\hbar}\right)\cdot\left(\frac{Ze\vec{L}}{mc\hbar r^3}\right)$$

$$\propto \vec{L}\cdot\vec{S} = J^2 - L^2 - S^2$$

for $\vec{J}$, the coupled angular momentum.

The electron spin angular momentum is given as $\vec{S}$, where the spin wavefunction is:



In :

ms = symbols('m_s')
spin = JzKet(S(1)/2, ms); spin




Out:

$${\left|\frac{1}{2},m_{s}\right\rangle }$$



From this we build our uncoupled state:



In :

state = TensorProduct(orbit, spin); state




Out:

$${{\left|l,m_{l}\right\rangle }}\otimes {{\left|\frac{1}{2},m_{s}\right\rangle }}$$



For clarity we will define $L^2$ and $S^2$ operators. These behave the same as J2, they only display differently.



In :

L2 = J2Op('L')
S2 = J2Op('S')



We also have the spin-orbit Hamiltonian:



In :

hso = J2 - TensorProduct(L2, 1) - TensorProduct(1, S2); hso




Out:

$$J^2 - {1}\otimes {S^2} - {L^2}\otimes {1}$$



Now we apply this to our state:



In :

apply1 = qapply(hso * state); apply1




Out:

$$- \hbar^{2} l^{2} {{\left|l,m_{l}\right\rangle }}\otimes {{\left|\frac{1}{2},m_{s}\right\rangle }} - \hbar^{2} l {{\left|l,m_{l}\right\rangle }}\otimes {{\left|\frac{1}{2},m_{s}\right\rangle }} + J^2 {{\left|l,m_{l}\right\rangle }}\otimes {{\left|\frac{1}{2},m_{s}\right\rangle }} - \frac{3}{4} \hbar^{2} {{\left|l,m_{l}\right\rangle }}\otimes {{\left|\frac{1}{2},m_{s}\right\rangle }}$$



Note this has not applied the coupled $J^2$ operator to the states, so we couple the states and apply again:



In :

apply2 = qapply(couple(apply1)); apply2




Out:

$$- \hbar^{2} l^{2} \sum_{j=m_{l} + m_{s}}^{l + \frac{1}{2}} C^{j,m_{l} + m_{s}}_{l,m_{l},\frac{1}{2},m_{s}} {\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\frac{1}{2}\right\rangle } - \hbar^{2} l \sum_{j=m_{l} + m_{s}}^{l + \frac{1}{2}} C^{j,m_{l} + m_{s}}_{l,m_{l},\frac{1}{2},m_{s}} {\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\frac{1}{2}\right\rangle } - \frac{3}{4} \hbar^{2} \sum_{j=m_{l} + m_{s}}^{l + \frac{1}{2}} C^{j,m_{l} + m_{s}}_{l,m_{l},\frac{1}{2},m_{s}} {\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\frac{1}{2}\right\rangle } + \sum_{j=m_{l} + m_{s}}^{l + \frac{1}{2}} \left(\hbar^{2} j^{2} C^{j,m_{l} + m_{s}}_{l,m_{l},\frac{1}{2},m_{s}} {\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\frac{1}{2}\right\rangle } + \hbar^{2} j C^{j,m_{l} + m_{s}}_{l,m_{l},\frac{1}{2},m_{s}} {\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\frac{1}{2}\right\rangle }\right)$$



We now collect the terms of the sum, since they share the same limits, and factor the result:



In :

subs = []
for sum_term in apply2.atoms(Sum):
subs.append((sum_term, sum_term.function))
limits = sum_term.limits
final = Sum(factor(apply2.subs(subs)), limits)
final




Out:

$$\sum_{j=m_{l} + m_{s}}^{l + \frac{1}{2}} \frac{1}{4} \hbar^{2} \left(4 j^{2} + 4 j - 4 l^{2} - 4 l -3\right) C^{j,m_{l} + m_{s}}_{l,m_{l},\frac{1}{2},m_{s}} {\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\frac{1}{2}\right\rangle }$$



This gives us the modification of the angular part of the spin-orbit Hamiltonian. We see there is now the new $j$ quantum number in the coupled states, which we see from looking at the equation will have values $l\pm \frac{1}{2}$, and $m_j=m_l + m_s$. We still have the $l$ and $s$ quantum numbers.