[1]:
import quanguru as qg
import numpy as np
import matplotlib.pyplot as plt

16b - Jaynes-Cummings Hamiltonian (in QuanGuru)#

The Jaynes-Cummings Hamiltonian is written as

\(H_{JC} = \hbar\omega_{c} a^{\dagger}a + \frac{1}{2}\hbar\omega_{q}\sigma_{z} + \hbar g(a^{\dagger}\sigma_{-} + a\sigma_{+})\)

where \(\sigma_{\pm} = (\sigma_{x} \pm i\sigma_{y})/2\) are raising/lowering operators for a two-level system, \(\sigma_{\mu}\) are the Pauli spin operators with \(\mu\in\{x,y,z\}\), \(a^{\dagger}\) and \(a\) are the creation and annihilation operators for the field mode, and \(\omega_{c}\), \(\omega_{q}\), and \(g\) are the cavity-field, qubit, and coupling (angular-) frequencies, respectively. Note that the above Hamiltonian is written in a common notation where the order of the sub-system Hilbert spaces is implicitly defined by the ordering in the coupling. This means, for example, that the composite form of the number operator is written explicitly as \((a^{\dagger}a)\otimes 1_{2,2}\) (similarly, \(a^{\dagger}\otimes\sigma_{-}\) and \(1_{d,d}\otimes\sigma_{z}\), where \(d\) is the truncation dimension for the cavity operators and \(\otimes\) is the tensor product).

In this tutorial, we describe/create the Jaynes-Cummings Hamiltonian using QuanGuru. For the parameters of the Hamiltonian, we will take \(\omega_{c} = \omega_{q} = g = 1/2\pi\) for simplicity. Since, QuanGuru uses frequencies (instead of angular-frequencies), frequencies are all 1. Also, instead of \(\sigma_{\pm} = (\sigma_{x} \pm i\sigma_{y})/2\), we will use \(J_{\pm} = (J_{x} \pm iJ_{y})/2\), where \(J_{\mu}\) (with \(\mu\in\{x,y,z\}\)) are the operators for large spins. With this approach, we will be able to extend the Jaynes-Cummings Hamiltonian to Tavis-Cumming Hamiltonian by simply setting a different j-value to our Qubit object.

[2]:
# create a composite system with a qubit and cavity
qubitJC = qg.Qubit(frequency=1, alias="JC_Qubit")
cavityJC = qg.Cavity(frequency=1, dimension=5, alias="JC_Cavity")

JCSystem = qubitJC + cavityJC

# couple the qubit and the cavity using their alias
couplingTerm_minusCreate = JCSystem.createTerm(qSystem=["JC_Qubit", "JC_Cavity"], operator=[qg.sigmam, qg.create], frequency=1)
couplingTerm_plusDestroy = JCSystem.createTerm(qSystem=["JC_Qubit", "JC_Cavity"], operator=[qg.sigmap, qg.destroy], frequency=1)

In the context of the Jaynes-Cummings Hamiltonian, the total Hamiltonian can be decomposed into diagonal and off-diagonal components, which represent different physical aspects of the system.

In QuanGuru, the total Hamiltonian of the system can be effectively analyzed by isolating its diagonal and off-diagonal components. This is achieved through the distinction between the subSys and terms Hamiltonians.

[3]:
# Hamiltonian of the total system
print(np.round(JCSystem.totalHamiltonian.toarray(), 2))
plt.imshow(JCSystem.totalHamiltonian.toarray())
plt.xticks([]); plt.yticks([])

[[ 0.5   0.    0.    0.    0.    0.    1.    0.    0.    0.  ]
 [ 0.    1.5   0.    0.    0.    0.    0.    1.41  0.    0.  ]
 [ 0.    0.    2.5   0.    0.    0.    0.    0.    1.73  0.  ]
 [ 0.    0.    0.    3.5   0.    0.    0.    0.    0.    2.  ]
 [ 0.    0.    0.    0.    4.5   0.    0.    0.    0.    0.  ]
 [ 0.    0.    0.    0.    0.   -0.5   0.    0.    0.    0.  ]
 [ 1.    0.    0.    0.    0.    0.    0.5   0.    0.    0.  ]
 [ 0.    1.41  0.    0.    0.    0.    0.    1.5   0.    0.  ]
 [ 0.    0.    1.73  0.    0.    0.    0.    0.    2.5   0.  ]
 [ 0.    0.    0.    2.    0.    0.    0.    0.    0.    3.5 ]]
[3]:
([], [])
../../../_images/classes_Tutorials_1_Qubit_16b_JaynesCummingsHamiltonianQuanGuru_4_2.png

The diagonal elements of the Hamiltonian, which correspond to the individual energies of the qubit and cavity, can be accessed through _subSysHamiltonian. This attribute contains the Hamiltonian of the subsystem without any interaction terms.

[4]:
# Hamiltonian containing only diagonal elements of the subsystem (qubit + cavity) without interaction terms
print(np.round(JCSystem._subSysHamiltonian.toarray(), 2))
plt.imshow(JCSystem._subSysHamiltonian.toarray())
plt.xticks([]); plt.yticks([])

[[ 0.5  0.   0.   0.   0.   0.   0.   0.   0.   0. ]
 [ 0.   1.5  0.   0.   0.   0.   0.   0.   0.   0. ]
 [ 0.   0.   2.5  0.   0.   0.   0.   0.   0.   0. ]
 [ 0.   0.   0.   3.5  0.   0.   0.   0.   0.   0. ]
 [ 0.   0.   0.   0.   4.5  0.   0.   0.   0.   0. ]
 [ 0.   0.   0.   0.   0.  -0.5  0.   0.   0.   0. ]
 [ 0.   0.   0.   0.   0.   0.   0.5  0.   0.   0. ]
 [ 0.   0.   0.   0.   0.   0.   0.   1.5  0.   0. ]
 [ 0.   0.   0.   0.   0.   0.   0.   0.   2.5  0. ]
 [ 0.   0.   0.   0.   0.   0.   0.   0.   0.   3.5]]
[4]:
([], [])
../../../_images/classes_Tutorials_1_Qubit_16b_JaynesCummingsHamiltonianQuanGuru_6_2.png

The off-diagonal elements, which represent the interaction between the qubit and the cavity, can be accessed through _termHamiltonian. These describe how the qubit and cavity interact and exchange energy.

[5]:
# Hamiltonian containging only off-diagonal elements of the interaction terms only
print(np.round(JCSystem._termHamiltonian.toarray(), 2))
plt.imshow(JCSystem._termHamiltonian.toarray())
plt.xticks([]); plt.yticks([])

[[0.   0.   0.   0.   0.   0.   1.   0.   0.   0.  ]
 [0.   0.   0.   0.   0.   0.   0.   1.41 0.   0.  ]
 [0.   0.   0.   0.   0.   0.   0.   0.   1.73 0.  ]
 [0.   0.   0.   0.   0.   0.   0.   0.   0.   2.  ]
 [0.   0.   0.   0.   0.   0.   0.   0.   0.   0.  ]
 [0.   0.   0.   0.   0.   0.   0.   0.   0.   0.  ]
 [1.   0.   0.   0.   0.   0.   0.   0.   0.   0.  ]
 [0.   1.41 0.   0.   0.   0.   0.   0.   0.   0.  ]
 [0.   0.   1.73 0.   0.   0.   0.   0.   0.   0.  ]
 [0.   0.   0.   2.   0.   0.   0.   0.   0.   0.  ]]
[5]:
([], [])
../../../_images/classes_Tutorials_1_Qubit_16b_JaynesCummingsHamiltonianQuanGuru_8_2.png