Implementing local gauge invariance with atomic mixtures.

This Notebook is based on the following paper, which was performed on the NaLi machine at SynQS. In this paper a new scalable analog quantum simulator of a U(1) gauge theory is demonstrated.

By using interspecies spin-changing collisions between particles, a gauge-invariant interaction between matter and gauge-field is achieved. In this case an atomic mixture of sodium and lithium is used.

We will model the system with two qudits of slightly different length. The first qudit is the matter field and the second qudit the gauge field.

import pennylane as qml

import numpy as np
import matplotlib.pyplot as plt

Make sure that you followed the necessary steps for obtaining the credentials as desribed in the introduction.

from pennylane_ls import *
from heroku_credentials import username, password

Rotating the matter field

we have to rotate the matter field to initialize the dynamics in the system first

NaLiDevice = qml.device(
    "synqs.mqs", wires=2, shots=500, username=username, password=password
)
@qml.qnode(NaLiDevice)
def matterpreparation(alpha=0):
    MultiQuditOps.load(2, wires=[0])
    MultiQuditOps.load(20, wires=[1])
    MultiQuditOps.rLx(alpha, wires=[1])
    obs = MultiQuditOps.Lz(0) @ MultiQuditOps.Lz(1)
    return qml.expval(obs)

visualize the circuit

matterpreparation(np.pi/2)
tensor([0.  , 9.97], requires_grad=True)
print(matterpreparation.draw())
 0: ──load(2)──────────────╭┤ ⟨Lz ⊗ Lz⟩ 
 1: ──load(20)──rLx(1.57)──╰┤ ⟨Lz ⊗ Lz⟩ 
NaLiDevice.job_id
'20211026_053958-multiqudit-synqs_test-d3e70'

now reproduce figure 1

alphas = np.linspace(0, np.pi, 15)
means = np.zeros((len(alphas), 2))
for i in range(len(alphas)):
    if i % 10 == 0:
        print("step", i)
    # Calculate the resulting states after each rotation
    means[i, :] = matterpreparation(alphas[i])
step 0
step 10
f, ax = plt.subplots()
ax.plot(alphas, means[:, 0], "o", label="gauge field")
ax.plot(alphas, means[:, 1], "o", label="matter field")
ax.set_ylabel(r"$\eta$")
ax.set_xlabel(r"$\varphi$")
ax.legend()
<matplotlib.legend.Legend at 0x1f416fe1af0>
_images/Gauge_Theory_13_1.png

time evolution

and now a time evolution

@qml.qnode(NaLiDevice)
def t_evolv(alpha=0, beta=0, gamma=0, delta=0, NLi=1, NNa=10, Ntrott=1):
    """Circuit that describes the time evolution.

    alpha ... Initial angle of rotation of the matter field
    beta ... Angle of rotation for the matter field
    gamma ... Angle of rotation on the squeezing term.
    delta ... Angle of rotation of the flip flop term.
    """
    # preparation step
    MultiQuditOps.load(NLi, wires=[0])
    MultiQuditOps.load(NNa, wires=[1])
    MultiQuditOps.rLx(alpha, wires=[1])

    # time evolution
    for ii in range(Ntrott):
        MultiQuditOps.LxLy(delta / Ntrott, wires=[0, 1])
        MultiQuditOps.rLz(beta / Ntrott, wires=[0])
        MultiQuditOps.rLz2(gamma / Ntrott, wires=[1])
    obs = MultiQuditOps.Lz(0)
    return qml.expval(obs)
t_evolv(alpha=np.pi / 2, beta=0.1, gamma=25, delta=0.2)
tensor(0.742, requires_grad=False)
print(t_evolv.draw())
 0: ──load(1)──────────────╭LxLy(0.2)──rLz(0.1)──┤ ⟨Lz⟩ 
 1: ──load(10)──rLx(1.57)──╰LxLy(0.2)──rLz2(25)──┤      

parameters of the experiment

Delta = -2 * np.pi * 500
chiT = 2.0 * np.pi * 0.01 * 300e3
lamT = 2.0 * np.pi * 2e-4 * 300e3;  # lamT = 2.*np.pi*2e-5*300e3;
Ntrott = 12
NLi = 5
NNa = 50
alpha = np.pi / 2
chi = chiT / NNa
lam = lamT / NNa;
times = np.linspace(0, 10.0, 10) * 1e-3
means = np.zeros(len(times))
for i in range(len(times)):
    means[i] = t_evolv(
        alpha, Delta * times[i], chi * times[i], lam * times[i], NLi, NNa, Ntrott=Ntrott
    )
f, ax = plt.subplots()
ax.plot(times * 1e3, means, "o", label="matter field")
ax.set_ylabel(r"$\eta$")
ax.set_xlabel("time (ms)")
ax.legend()
<matplotlib.legend.Legend at 0x1f4177f29d0>
_images/Gauge_Theory_22_1.png