Skip to content

Commit 4c48741

Browse files
committed
Update to latest version of QuantumControl
1 parent 1a40588 commit 4c48741

File tree

7 files changed

+38
-53
lines changed

7 files changed

+38
-53
lines changed

Project.toml

+16-14
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ authors = ["Michael Goerz <mail@michaelgoerz.net>"]
44
version = "0.1.0-dev"
55

66
[deps]
7+
AppleAccelerate = "13e28ba4-7ad8-5781-acae-3021b1ed3924"
78
DisplayAs = "0b91fe84-8a4c-11e9-3e1d-67c38462b6d6"
89
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
910
DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
@@ -31,29 +32,30 @@ UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
3132
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
3233

3334
[compat]
35+
AppleAccelerate = "0.4.0"
3436
DisplayAs = "0.1.6"
35-
Documenter = "1.4"
37+
Documenter = "1.8"
3638
DocumenterCitations = "1.3"
37-
DocumenterInterLinks = "0.2"
38-
GRAPE = "0.6.2"
39-
GRAPELinesearchAnalysis = "0.7.0"
39+
DocumenterInterLinks = "1.0"
40+
GRAPE = "0.7.5"
41+
GRAPELinesearchAnalysis = "0.7.2"
4042
Glob = "1.3"
4143
JuliaFormatter = "1.0"
42-
Krotov = "0.6.2"
43-
LineSearches = "7.2"
44+
Krotov = "0.7.2"
45+
LineSearches = "7.3"
4446
LinearAlgebra = "1"
45-
Literate = "2.16"
46-
LiveServer = "1.2"
47+
Literate = "2.20"
48+
LiveServer = "1.4"
4749
Optim = "1.7"
4850
Plots = "1.39"
49-
QuantumControl = "0.9.1"
50-
QuantumControlTestUtils = "0.3.0"
51-
QuantumPropagators = "0.7.6"
51+
QuantumControl = "0.11.1"
52+
QuantumControlTestUtils = "0.3.1"
53+
QuantumPropagators = "0.8.3"
5254
SafeTestsets = "0.1"
5355
SparseArrays = "1.10"
5456
TOML = "1"
5557
Test = "1"
56-
TwoQubitWeylChamber = "0.1.3"
57-
UnicodePlots = "3.6"
58+
TwoQubitWeylChamber = "0.2.1"
59+
UnicodePlots = "3.7.1"
5860
Zygote = "0.6"
59-
julia = "1.10"
61+
julia = "1.11"

docs/src/refs.bib

+1-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ @article{GoerzQ2022
172172

173173

174174
@article{GoerzPRA2015,
175-
Author = {Goerz, Michael H. and Gualdi, Giulia and Reich, Daniel M. and Koch, Christiane P. and Motzoi, Felix and Whaley, K. Birgitta and Vala, Ji\vr\'i and Müller, Matthias M. and Montangero, Simone and Calarco, Tommaso},
175+
Author = {Goerz, Michael H. and Gualdi, Giulia and Reich, Daniel M. and Koch, Christiane P. and Motzoi, Felix and Whaley, K. Birgitta and Vala, Jiří and Müller, Matthias M. and Montangero, Simone and Calarco, Tommaso},
176176
Title = {Optimizing for an arbitrary perfect entangler. II. Application},
177177
Journal = pra,
178178
Year = {2015},

examples/grape_state_to_state/simple_state_to_state.jl

+16-38
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,13 @@ datadir(names...) = joinpath(@__DIR__, names...)
4343

4444
using QuantumControl
4545
using QuantumPropagators: ExpProp
46+
using AppleAccelerate #hide
4647

4748
using Test #src
4849

4950
# ## Two-level Hamiltonian
5051

51-
# We consider the Hamiltonian $\op{H}_{0} = - \frac{\omega}{2} \op{\sigma}_{z}$, representing a simple qubit with energy level splitting $\omega$ in the basis $\{\ket{0},\ket{1}\}$. The control field $\epsilon(t)$ is assumed to couple via the Hamiltonian $\op{H}_{1}(t) = \epsilon(t) \op{\sigma}_{x}$ to the qubit, i.e., the control field effectively drives transitions between both qubit states.
52-
#
53-
# We we will use
52+
# We consider the Hamiltonian ``\op{H}_{0} = - \frac{\omega}{2} \op{\sigma}_{z}``, representing a simple qubit with energy level splitting ``\omega`` in the basis ``\{\ket{0},\ket{1}\}``. The control field ``\epsilon(t)`` is assumed to couple via the Hamiltonian ``\op{H}_{1}(t) = \epsilon(t) \op{\sigma}_{x}`` to the qubit, i.e., the control field effectively drives transitions between both qubit states.
5453

5554
ϵ(t) = 0.2 * QuantumControl.Shapes.flattop(t, T=5, t_rise=0.3, func=:blackman);
5655

@@ -74,10 +73,7 @@ end;
7473
H = tls_hamiltonian();
7574
@test length(H.ops) == 2 #src
7675

77-
# The control field here switches on from zero at $t=0$ to it's maximum amplitude
78-
# 0.2 within the time period 0.3 (the switch-on shape is half a [Blackman pulse](https://en.wikipedia.org/wiki/Window_function#Blackman_window)).
79-
# It switches off again in the time period 0.3 before the
80-
# final time $T=5$). We use a time grid with 500 time steps between 0 and $T$:
76+
# The control field here switches on from zero at ``t=0`` to it's maximum amplitude 0.2 within the time period 0.3 (the switch-on shape is half a [Blackman pulse](https://en.wikipedia.org/wiki/Window_function#Blackman_window)). It switches off again in the time period 0.3 before the final time ``T=5``). We use a time grid with 500 time steps between 0 and ``T``:
8177

8278
tlist = collect(range(0, 5, length=500));
8379

@@ -115,15 +111,15 @@ using LinearAlgebra #src
115111
@test dot(ket(0), ket(1)) 0 #src
116112
#-
117113

118-
# The physical objective of our optimization is to transform the initial state $\ket{0}$ into the target state $\ket{1}$ under the time evolution induced by the Hamiltonian $\op{H}(t)$.
114+
# The physical objective of our optimization is to transform the initial state ``\ket{0}`` into the target state ``\ket{1}`` under the time evolution induced by the Hamiltonian ``\op{H}(t)``.
119115

120116
trajectories = [Trajectory(initial_state=ket(0), generator=H, target_state=ket(1))];
121117

122118
#-
123119
@test length(trajectories) == 1 #src
124120
#-
125121

126-
# The full control problem includes this trajectory, information about the time grid for the dynamics, and the functional to be used (the square modulus of the overlap $\tau$ with the target state in this case).
122+
# The full control problem includes this trajectory, information about the time grid for the dynamics, and the functional to be used (the square modulus of the overlap ``\tau`` with the target state in this case).
127123

128124
using QuantumControl.Functionals: J_T_sm
129125

@@ -142,7 +138,7 @@ problem = ControlProblem(
142138

143139
# ## Simulate dynamics under the guess field
144140

145-
# Before running the optimization procedure, we first simulate the dynamics under the guess field $\epsilon_{0}(t)$. The following solves equation of motion for the defined trajective, which contains the initial state $\ket{\Psi_{\init}}$ and the Hamiltonian $\op{H}(t)$ defining its evolution.
141+
# Before running the optimization procedure, we first simulate the dynamics under the guess field ``\epsilon_{0}(t)``. The following solves equation of motion for the defined trajectory, which contains the initial state ``\ket{\Psi_{\init}}`` and the Hamiltonian ``\op{H}(t)`` defining its evolution.
146142

147143

148144
guess_dynamics = propagate_trajectory(
@@ -166,43 +162,30 @@ display(fig) #src
166162

167163
# ## Optimization with LBFGSB
168164

169-
# In the following we optimize the guess field $\epsilon_{0}(t)$ such that the intended state-to-state transfer $\ket{\Psi_{\init}} \rightarrow \ket{\Psi_{\tgt}}$ is solved.
165+
# In the following we optimize the guess field ``\epsilon_{0}(t)`` such that the intended state-to-state transfer ``\ket{\Psi_{\init}} \rightarrow \ket{\Psi_{\tgt}}`` is solved.
170166

171-
# The GRAPE package performs the optimization by calculating the gradient of $J_T$ with respect to the values of the control field at each point in time. This gradient is then fed into a backend solver that calculates an appropriate update based on that gradient.
167+
# The GRAPE package performs the optimization by calculating the gradient of ``J_T`` with respect to the values of the control field at each point in time. This gradient is then fed into a backend solver that calculates an appropriate update based on that gradient.
172168

173169
using GRAPE
174170

175-
# By default, this backend is [LBFGSB.jl](https://github.com/Gnimuc/LBFGSB.jl), a wrapper around the true and tested [L-BFGS-B Fortran library](http://users.iems.northwestern.edu/%7Enocedal/lbfgsb.html). L-BFGS-B is a pseudo-Hessian method: it efficiently estimates the second-order Hessian from the gradient information. The search direction determined from that Hessian dramatically improves convergence compared to using the gradient directly as a search direction. The L-BFGS-B method performs its own linesearch to determine how far to go in the search direction.
176-
177-
# It can be quite instructive to see how the improvement in the pseudo-Hessian search direction compares to the gradient, how the linesearch finds an appropriate step width. For this purpose, we have a [GRAPELinesearchAnalysis](https://github.com/JuliaQuantumControl/GRAPELinesearchAnalysis.jl) package that automatically generates plots in every iteration of the optimization showing the linesearch behavior
178-
179-
using GRAPELinesearchAnalysis
180-
181-
# We feed this into the optimization as part of the `info_hook`.
171+
# By default, this backend is [`LBFGSB.jl`](https://github.com/Gnimuc/LBFGSB.jl), a wrapper around the true and tested [L-BFGS-B Fortran library](http://users.iems.northwestern.edu/%7Enocedal/lbfgsb.html). L-BFGS-B is a pseudo-Hessian method: it efficiently estimates the second-order Hessian from the gradient information. The search direction determined from that Hessian dramatically improves convergence compared to using the gradient directly as a search direction. The L-BFGS-B method performs its own linesearch to determine how far to go in the search direction.
182172

183173
opt_result_LBFGSB = @optimize_or_load(
184174
datadir("TLS", "GRAPE_opt_result_LBFGSB.jld2"),
185175
problem;
186176
method=GRAPE,
187177
prop_method=ExpProp,
188-
info_hook=(
189-
GRAPELinesearchAnalysis.plot_linesearch(datadir("TLS", "Linesearch", "LBFGSB")), #md
190-
GRAPELinesearchAnalysis.plot_linesearch(datadir("TLS", "Linesearch", "LBFGSB")), #nb
191-
GRAPE.print_table,
192-
)
193178
);
194179
#-
195180
@test opt_result_LBFGSB.J_T < 1e-3 #src
196181
#-
197182

198-
# When going through this tutorial locally, the [generated images for the linesearch](https://github.com/JuliaQuantumControl/GRAPE.jl/tree/data-dump/TLS/Linesearch/LBFGSB) can be found in `datadir("TLS", "Linesearch, "LBFGS")`
199-
200183
opt_result_LBFGSB
201184

202185
# We can plot the optimized field:
203186

204187
#-
205-
fig = plot_control(opt_result_LBFGSB.optimized_controls[1], tlist)
188+
fig = plot_control(opt_result_LBFGSB.optimized_controls[1], tlist) # This is test
206189
#md fig |> DisplayAs.PNG #hide
207190
display(fig) #src
208191
#-
@@ -212,7 +195,7 @@ display(fig) #src
212195

213196
# Our GRAPE implementation includes the analytic gradient of the optimization functional `J_T_sm`. Thus, we only had to pass the functional itself to the optimization. More generally, for functionals where the analytic gradient is not known, semi-automatic differentiation can be used to determine it automatically. For illustration, we may re-run the optimization forgoing the known analytic gradient and instead using an automatically determined gradient.
214197

215-
# As shown in Goerz et al., arXiv:2205.15044, by evaluating the gradient of ``J_T`` via a chain rule in the propagated states, the dependency of the gradient on the final time functional is pushed into the boundary condition for the backward propagation, ``|χ_k⟩ = -∂J_T/∂⟨ϕ_k|``. For functionals that can be written in terms of the overlaps ``τ_k`` of the forward-propagated states and target states, such as the `J_T_sm` used here, a further chain rule leaves derivatives of `J_T` with respect to the overlaps ``τ_k``, which are easily obtained via automatic differentiation. The `optimize` function takes an optional parameter `chi` that may be passed a function to calculate ``|χ_k⟩``. A suitable function can be obained using
198+
# As shown in Goerz et al., arXiv:2205.15044, by evaluating the gradient of ``J_T`` via a chain rule in the propagated states, the dependency of the gradient on the final time functional is pushed into the boundary condition for the backward propagation, ``|χ_k⟩ = -∂J_T/∂⟨ϕ_k|``. For functionals that can be written in terms of the overlaps ``τ_k`` of the forward-propagated states and target states, such as the `J_T_sm` used here, a further chain rule leaves derivatives of `J_T` with respect to the overlaps ``τ_k``, which are easily obtained via automatic differentiation. The `optimize` function takes an optional parameter `chi` that may be passed a function to calculate ``|χ_k⟩``. A suitable function can be obtained using
216199

217200
using QuantumControl.Functionals: make_chi
218201

@@ -232,26 +215,21 @@ opt_result_LBFGSB_via_χ
232215

233216
# ## Optimization with Optim.jl
234217

235-
# As an alternative to the default L-BFGS-B backend, we can also use any of the gradient-based optimizers in [Optiml.jl](https://github.com/JuliaNLSolvers/Optim.jl). This also gives full control over the linesearch method.
218+
# As an alternative to the default L-BFGS-B backend, we can also use any of the gradient-based optimizers in [`Optim.jl`](https://github.com/JuliaNLSolvers/Optim.jl). This also gives full control over the linesearch method.
236219

237220
import Optim
238221
import LineSearches
239222

240-
# Here, we use the LBFGS implementation that is part of Optim (which is not exactly the same as L-BFGS-B; "B" being the variant of LBFGS with optional additional bounds on the control) with a Hager-Zhang linesearch
223+
# Here, we use the LBFGS implementation that is part of `Optim` (which is not exactly the same as L-BFGS-B; "B" being the variant of LBFGS with optional additional bounds on the control) with a Hager-Zhang linesearch
241224

242225
opt_result_OptimLBFGS = @optimize_or_load(
243226
datadir("TLS", "GRAPE_opt_result_OptimLBFGS.jld2"),
244227
problem;
245228
method=GRAPE,
246-
info_hook=(
247-
GRAPELinesearchAnalysis.plot_linesearch(datadir("TLS", "Linesearch", "OptimLBFGS")), #md
248-
GRAPELinesearchAnalysis.plot_linesearch(datadir("TLS", "Linesearch", "OptimLBFGS")), #nb
249-
GRAPE.print_table,
250-
),
251229
optimizer=Optim.LBFGS(;
252230
alphaguess=LineSearches.InitialStatic(alpha=0.2),
253231
linesearch=LineSearches.HagerZhang(alphamax=2.0)
254-
)
232+
),
255233
);
256234

257235
#-
@@ -267,13 +245,13 @@ fig = plot_control(opt_result_OptimLBFGS.optimized_controls[1], tlist)
267245
#md fig |> DisplayAs.PNG #hide
268246
display(fig) #src
269247

270-
# We can see that the choice of linesearch parameters in particular strongly influence the convergence and the resulting field. Play around with different methods and parameters, and compare the different [plots generated by `GRAPELinesearchAnalysis`](https://github.com/JuliaQuantumControl/GRAPE.jl/tree/data-dump/TLS/Linesearch/OptimLBFGS)!
248+
# We can see that the choice of linesearch parameters in particular strongly influence the convergence and the resulting field. Play around with different methods and parameters!
271249
#
272250
# Empirically, we find the default L-BFGS-B to have a very well-behaved linesearch.
273251

274252
# ## Simulate the dynamics under the optimized field
275253

276-
# Having obtained the optimized control field, we can simulate the dynamics to verify that the optimized field indeed drives the initial state $\ket{\Psi_{\init}} = \ket{0}$ to the desired target state $\ket{\Psi_{\tgt}} = \ket{1}$.
254+
# Having obtained the optimized control field, we can simulate the dynamics to verify that the optimized field indeed drives the initial state ``\ket{\Psi_{\init}} = \ket{0}`` to the desired target state ``\ket{\Psi_{\tgt}} = \ket{1}``.
277255

278256
using QuantumControl.Controls: substitute
279257

examples/perfect_entanglers/perfect_entanglers.jl

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#md import DisplayAs #hide
4242
datadir(names...) = joinpath(@__DIR__, names...);
4343
using Test #src
44+
using AppleAccelerate #hide
4445

4546
# This example illustrates the optimization towards a perfectly entangling
4647
# two-qubit gate for a system of two transmon qubits with a shared transmission

examples/rho_3states/rho_3states.jl

+2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ datadir(names...) = joinpath(@__DIR__, names...);
4848
using QuantumControl
4949
using LinearAlgebra
5050
using Serialization
51+
using AppleAccelerate #hide
52+
5153
using SparseArrays
5254
#-
5355
using Plots

src/run_examples.jl

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ function run_example(
142142
@info "skip converting `$(_shrinkuser(file))` to .ipynb file (up to date)."
143143
else
144144
_run(_script_run_notebook(folder); threads)
145+
run(`jupyter trust $nbfile`; wait=true)
145146
end
146147
end
147148
end

tutorials/krotov_pulse_parameterization/krotov_pulse_parameterization.jl

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ using QuantumControl.PulseParameterizations:
5555
ParameterizedAmplitude
5656
using QuantumPropagators: ExpProp
5757
using LinearAlgebra
58+
using AppleAccelerate #hide
5859

5960
#-
6061
using Test #src

0 commit comments

Comments
 (0)