Time-optimal Rydberg Blockade Gate
In this example we simulate a two-qubit Rydberg blockade gate performed using a shaped laser pulse following Jandura & Pupillo, Quantum 6, 712 (2022).
We use a Pulse instruction with custom defined pulse amplitude
using AtomTwin
using Printf
using PlotsParameters
Ω = 2π * 1.0e6 # Rabi frequency (rad/s)
V = 2π * 10.0e6 # Blockade strength
pulse_duration = 7.612e-6/2π # Total pulse duration (s)
dt = 1e-9 # Time step (s)System definition
Define two three-level atoms with states |0⟩, |1⟩ and |r⟩
zero, one, r = Level("0"), Level("1"), Level("r")
atoms = [Atom(; levels = [zero, one, r]) for _ in 1:2]
system = System(atoms)Add a coherent resonant drive between |1⟩ and |r⟩ with Rabi frequency Ω this is the coupling that will be modified by the time-optimal pulse shape
couplings = add_coupling!(system, atoms, one => r, Ω; active = false)Add a Rydberg blockade interaction with strength V
interaction = add_interaction!(system, (atoms[1],atoms[2]), (r, r) => (r, r), V)Build sequence
We're going to plot the Rydberg population as a function of time, so lets register population detectors on |r⟩ for each atom
add_detector!(system, PopulationDetectorSpec(atoms[1], r; name = "P_r1"))
add_detector!(system, PopulationDetectorSpec(atoms[2], r; name = "P_r2"))Time-optimal pulse shape from Jandura & Pupillo, Quantum 6, 712 (2022)
amplitudes = cis.(-[0,
-0.00520685612112193,
-0.0155559081588863,
-0.0308285428692611,
-0.0510421373004286,
-0.0757448285164276,
-0.104800944811622,
-0.137947539521238,
-0.174889573600685,
-0.215142997613728,
-0.258294623823603,
-0.304178101159189,
-0.352019428558297,
-0.401594848150014,
-0.45228883521041,
-0.503706714556176,
-0.555290018806423,
-0.606558953046575,
-0.656841586100419,
-0.706018505236382,
-0.753191069154603,
-0.798144574015789,
-0.840346172440943,
-0.879455302902513,
-0.915066204060227,
-0.946844618938562,
-0.974328444072949,
-0.997548987218437,
-1.01609870894535,
-1.02964270060675,
-1.03830624739873,
-1.04170068037541,
-1.03991189301145,
-1.03273476275601,
-1.02033617790978,
-1.00268600509327,
-0.979886133680442,
-0.951962901081124,
-0.919103804352448,
-0.881498486677938,
-0.839519038173743,
-0.79329814890767,
-0.743240724378473,
-0.689739845766647,
-0.633156065410953,
-0.573981695867087,
-0.512648277245333,
-0.449730092038307,
-0.385685098302023,
-0.321064299740322,
-0.256469451967428,
-0.19248736102722,
-0.129441078090281,
-0.0683019710232431,
-0.00926042041886888,
0.0475242671082795,
0.100836667323695,
0.151000933428868,
0.197191385073937,
0.239332270886053,
0.276642347994639,
0.309530918583325,
0.337616228882048,
0.360459445871596,
0.378000581352638,
0.39041393288355,
0.397416886561685,
0.399524192258912,
0.395995640837166,
0.387279007216751,
0.373673929127344,
0.35525453644305,
0.332164479176917,
0.304652616274093,
0.272856720847748,
0.237233191283938,
0.198141166542208,
0.156009259564589,
0.110989895357531,
0.0637406719662517,
0.0147896100480912,
-0.0357093980739526,
-0.0869606645257641,
-0.138580326486527,
-0.189935228970358,
-0.240724197891832,
-0.290386349074185,
-0.338279019260814,
-0.384132052601118,
-0.427272497801067,
-0.46755477276085,
-0.504407998449411,
-0.537406687035639,
-0.566619049764934,
-0.591244574420264,
-0.611262863634426,
-0.626683378226236,
-0.636988051044744,
-0.642117952429648
])Build a pulse sequence with time-dependent amplitudes
seq = Sequence(dt)
@sequence seq begin
Pulse(couplings, pulse_duration; amplitudes=amplitudes)
endRun simulations
For now we can't do two atom tomography, so we manually construct the truth table for this gate'
computational_basis = [[zero,zero], [zero,one],[one,zero],[one,one]]
println("Time-optimal Rydberg blockade gate truth table")
println("Input | Output | Probability | ⟨out|U|in⟩")
println("──────┼────────┼─────────────┼──────────────────")
for input in computational_basis
input_str = join([i.label for i in input])
result = play(system, seq; initial_state=input, savefinalstate=true) # Run once per input
final_state = result.final_states[1]
output_str = input_str # For CZ, the output should be the same computational state
finalstate = getqstate(system, input)
prob = abs2(finalstate' * final_state) # Probability to return to the input state
amp = finalstate' * final_state # Compute matrix element |⟨input|U|input⟩|²
@printf "%4s | %4s | %.3e | %s\n" input_str output_str prob amp
endWe can also reproduce figure 1d from the paper by looking at the time-dependent Rydberg population for two initial states
out01 = play(system, seq; initial_state = [zero,one] )
out11 = play(system, seq; initial_state = [one,one] )Plot results
Collect data
tlist = out01.times # Time grid (s)
t_us = tlist .* 1e6 # Convert to microseconds
P_0r = out01.detectors["P_r1"] + out01.detectors["P_r2"]
P_W = out11.detectors["P_r1"] + out11.detectors["P_r2"]Create a plot showing:
- Population in the |0r⟩ state (blue)
- Population in the |W⟩ = 1/sqrt(2)(|1r⟩ + |r1⟩) state (orange)
plt = Plots.plot(
t_us, P_0r;
label = "P_0r",
xlabel = "Time (μs)",
ylabel = "Rydberg-state population",
title = "Time-optimal Rydberg blockade gate",
linewidth = 2,
color = :blue,
)
Plots.plot!(plt, t_us, P_W; label= "P_W", color = :orange, linewidth=2)
pltThis page was generated using Literate.jl.