-
Notifications
You must be signed in to change notification settings - Fork 0
/
rabi_calibration.jl
142 lines (126 loc) · 4.8 KB
/
rabi_calibration.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using IonSim
using QuantumOptics: timeevolution, stochastic
using StochasticDiffEq
using ScikitLearn
using Random
using Optim
using Distributions
function rabi_calibration(detuning, pi_time, initial_guess, N, tspan_ideal, tspan_experiment, timescale=1e-6)
ca_ion = Ca40(["S-1/2", "D-1/2"])
chain = LinearChain(
ions=[ca_ion],
com_frequencies=(x=3e6,y=3e6,z=1e6),
vibrational_modes=(;z=[1]),
)
laser = Laser(
k = (x̂ + ẑ)/√2,
ϵ = (x̂ - ẑ)/√2,
)
trap = Trap(configuration=chain, B=4e-4, Bhat=ẑ, δB=0, lasers=[laser])
laser.Δ = transition_frequency(trap, 1, ("S-1/2", "D-1/2"))
function simulate_trap(tspan)
detuned_laser = copy(laser)
detuned_laser.Δ += detuning
trap.lasers = [detuned_laser]
Efield_from_pi_time!(pi_time*timescale, trap, 1, 1, ("S-1/2", "D-1/2"));
h = hamiltonian(trap, timescale=timescale)
mode = trap.configuration.vibrational_modes.z[1]
@time tout, sol = timeevolution.schroedinger_dynamic(tspan, ionstate(trap, "S-1/2") ⊗ mode[0], h)
ex = real.(expect(ionprojector(trap, "D-1/2"), sol))
return tout, ex
end;
tout, ideal_ex = simulate_trap(tspan_ideal);
# function to simulate taking real data
function sample(expectation_values)
samples = []
for p in expectation_values
number = rand(Float64)
if p <= number
push!(samples, 0)
else
push!(samples, 1)
end
end
return samples
end;
function simulate_experiment(n_shots)
_, expectation_values = simulate_trap(tspan_experiment)
counts = sample(expectation_values)
for n = 2:n_shots
counts += sample(expectation_values)
end
return counts
end;
# let's just use the traditional pure state theory
function prob_1(time, θ₁, θ₂)
sigX = [0 1; 1 0]
sigZ = [1 0; 0 -1]
H = 0.5*θ₁*sigX - 0.5*θ₂*sigZ
U = exp(-im*H*time)
return abs([0, 1]'*U*[1, 0])^2
end;
function log_likelihood(bright_counts, num_experiments, times, θ₁, θ₂)
out = 0
for i in eachindex(times)
p_1 = prob_1(times[i], θ₁, θ₂)
dist = Multinomial(num_experiments, [1-p_1, p_1])
term = logpdf(dist, [num_experiments-bright_counts[i], bright_counts[i]])
if term != NaN
out += term
end
end
return out
end;
# run the experiment, learn the model, and reconstruct the curve from the learned model
bright_counts = simulate_experiment(N);
function objective(θ::Vector)
return -log_likelihood(bright_counts, N, tspan_experiment, θ[1], θ[2])
end
res = optimize(objective, initial_guess)
θ₁, θ₂ = Optim.minimizer(res)
predicted_ex = []
for t in tspan_ideal
push!(predicted_ex, prob_1(t, θ₁, θ₂))
end
# also find the fit params for the ideal curve
ideal_bright_counts = simulate_experiment(1000000);
function objective_ideal(θ::Vector)
return -log_likelihood(ideal_bright_counts, 1000000, tspan_experiment, θ[1], θ[2])
end
res = optimize(objective_ideal, initial_guess)
ideal_θ₁, ideal_θ₂ = Optim.minimizer(res)
return Dict(
"ideal_curve" => ideal_ex,
"ideal_fit_params" => [ideal_θ₁, ideal_θ₂],
"experimental_data" => bright_counts / N,
"learned_curve" => predicted_ex,
"learned_fit_params" => [θ₁, θ₂],
)
end
function rabi_fidelity(actual_detuning, actual_pi_time, learned_detuning, learned_pi_time, timescale=1e-6)
ca_ion = Ca40(["S-1/2", "D-1/2"])
chain = LinearChain(
ions=[ca_ion],
com_frequencies=(x=3e6,y=3e6,z=1e6),
vibrational_modes=(;z=[1]),
)
laser = Laser(
k = (x̂ + ẑ)/√2,
ϵ = (x̂ - ẑ)/√2,
)
trap = Trap(configuration=chain, B=4e-4, Bhat=ẑ, δB=0, lasers=[laser])
laser.Δ = transition_frequency(trap, 1, ("S-1/2", "D-1/2"))
# adjust the laser frequency by the error in the learned detuning
detuned_laser = copy(laser)
learned_detuning_error = actual_detuning - learned_detuning
detuned_laser.Δ += learned_detuning_error
trap.lasers = [detuned_laser]
# the E-field corresponds to the actual pi time, but we will evolve for the learned pi time
Efield_from_pi_time!(actual_pi_time*timescale, trap, 1, 1, ("S-1/2", "D-1/2"));
tspan = [0, learned_pi_time]
h = hamiltonian(trap, timescale=timescale)
mode = trap.configuration.vibrational_modes.z[1]
@time tout, sol = timeevolution.schroedinger_dynamic(tspan, ionstate(trap, "S-1/2") ⊗ mode[0], h)
ex = real.(expect(ionprojector(trap, "D-1/2"), sol))
return ex[end]
end