From dbf67a4ede25692b006a3e3675f1b2de6ea82507 Mon Sep 17 00:00:00 2001 From: Gennadi Ryan Date: Tue, 8 Jul 2025 17:46:28 -0400 Subject: [PATCH 1/8] Adding back plotting --- docs/literate/examples/two_qubit_gates.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/literate/examples/two_qubit_gates.jl b/docs/literate/examples/two_qubit_gates.jl index b0781a9b..50d1ead3 100644 --- a/docs/literate/examples/two_qubit_gates.jl +++ b/docs/literate/examples/two_qubit_gates.jl @@ -34,8 +34,8 @@ using PiccoloQuantumObjects using NamedTrajectories using LinearAlgebra -# `using PiccoloPlots` -# `using CairoMakie` +using PiccoloPlots +using CairoMakie ⊗(a, b) = kron(a, b) @@ -116,7 +116,7 @@ println(fid_final) # Looks good! # Now let's plot the pulse and the population trajectories for the first two columns of the unitary, i.e. initial state of $\ket{00}$ and $\ket{01}$. For this we provide the function [`plot_unitary_populations`](@ref). -# `plot_unitary_populations(prob.trajectory)` +plot_unitary_populations(prob.trajectory) # For fun, let's look at a minimum time pulse for this problem @@ -126,7 +126,7 @@ fid_final_min_time = unitary_rollout_fidelity(min_time_prob.trajectory, sys) println(fid_final_min_time) # And let's plot this solution -# `plot_unitary_populations(min_time_prob.trajectory)` +plot_unitary_populations(min_time_prob.trajectory) # It looks like our pulse derivative bounds are holding back the solution, but regardless, the duration has decreased: duration = get_duration(prob.trajectory) @@ -183,7 +183,7 @@ println(fid_final) # Again, looks good! # Now let's plot the pulse and the population trajectories for the first two columns of the unitary, i.e. initial state of $\ket{00}$ and $\ket{01}$. -# `plot_unitary_populations(prob.trajectory)` +plot_unitary_populations(prob.trajectory) # For fun, let's look at a minimum time pulse for this problem @@ -193,7 +193,7 @@ fid_final_min_time = unitary_rollout_fidelity(min_time_prob.trajectory, sys) println(fid_final_min_time) # And let's plot this solution -# `plot_unitary_populations(min_time_prob.trajectory)` +plot_unitary_populations(min_time_prob.trajectory) # It looks like our pulse derivative bounds are holding back the solution, but regardless, the duration has decreased: From 055b8045cd4bf9e45461e106e0042d154232e06f Mon Sep 17 00:00:00 2001 From: Gennadi Ryan Date: Tue, 8 Jul 2025 17:58:51 -0400 Subject: [PATCH 2/8] Updating project file --- docs/Project.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Project.toml b/docs/Project.toml index 8df91abc..eaecb613 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,8 +1,10 @@ [deps] +CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589" NamedTrajectories = "538bc3a1-5ab9-4fc3-b776-35ca1e893e08" +PiccoloPlots = "f42a522c-b487-4f73-ad5a-ad0c3e4a12c8" PiccoloQuantumObjects = "5a402ddf-f93c-42eb-975e-5582dcda653d" QuantumCollocation = "0dc23a59-5ffb-49af-b6bd-932a8ae77adf" Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" From 80ccf6fa03443a954a36f2c605ea12a6eba13ee3 Mon Sep 17 00:00:00 2001 From: Gennadi Ryan Date: Tue, 8 Jul 2025 19:11:22 -0400 Subject: [PATCH 3/8] Formatting --- docs/literate/examples/two_qubit_gates.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/literate/examples/two_qubit_gates.jl b/docs/literate/examples/two_qubit_gates.jl index 50d1ead3..fc0683ca 100644 --- a/docs/literate/examples/two_qubit_gates.jl +++ b/docs/literate/examples/two_qubit_gates.jl @@ -135,6 +135,7 @@ println(duration, " - ", min_time_duration, " = ", duration - min_time_duration) + # ## Mølmer–Sørensen gate # Here we will solve for a [Mølmer–Sørensen gate](https://en.wikipedia.org/wiki/M%C3%B8lmer%E2%80%93S%C3%B8rensen_gate) between two. The gate is generally described, for N qubits, by the unitary matrix From e27275adc0ad7dbf7bf00575aee693462880c49c Mon Sep 17 00:00:00 2001 From: Gennadi Ryan Date: Tue, 8 Jul 2025 20:21:32 -0400 Subject: [PATCH 4/8] Adding multilevel transmon example --- docs/literate/examples/multilevel_transmon.jl | 120 ++++++++++++++++++ docs/make.jl | 1 + 2 files changed, 121 insertions(+) create mode 100644 docs/literate/examples/multilevel_transmon.jl diff --git a/docs/literate/examples/multilevel_transmon.jl b/docs/literate/examples/multilevel_transmon.jl new file mode 100644 index 00000000..e6edd926 --- /dev/null +++ b/docs/literate/examples/multilevel_transmon.jl @@ -0,0 +1,120 @@ +# # Multilevel Transmon + +# In this example we will look at a multilevel transmon qubit with a Hamiltonian given by +# +# ```math +# \hat{H}(t) = -\frac{\delta}{2} \hat{n}(\hat{n} - 1) + u_1(t) (\hat{a} + \hat{a}^\dagger) + u_2(t) i (\hat{a} - \hat{a}^\dagger) +# ``` +# where $\hat{n} = \hat{a}^\dagger \hat{a}$ is the number operator, $\hat{a}$ is the annihilation operator, $\delta$ is the anharmonicity, and $u_1(t)$ and $u_2(t)$ are control fields. +# +# We will use the following parameter values: +# +# ```math +# \begin{aligned} +# \delta &= 0.2 \text{ GHz}\\ +# \abs{u_i(t)} &\leq 0.2 \text{ GHz}\\ +# T_0 &= 10 \text{ ns}\\ +# \end{aligned} +# ``` +# +# For convenience, we have defined the `TransmonSystem` function in the `QuantumSystemTemplates` module, which returns a `QuantumSystem` object for a transmon qubit. We will use this function to define the system. + +# ## Setting up the problem + +# To begin, let's load the necessary packages, define the system parameters, and create a a `QuantumSystem` object using the `TransmonSystem` function. + +using QuantumCollocation +using PiccoloQuantumObjects +using NamedTrajectories +using LinearAlgebra +using SparseArrays +using Random; Random.seed!(123) + +using PiccoloPlots +using CairoMakie + +## define the time parameters + +T₀ = 10 # total time in ns +T = 50 # number of time steps +Δt = T₀ / T # time step + +## define the system parameters +levels = 5 +δ = 0.2 + +## add a bound to the controls +a_bound = 0.2 + +## create the system +sys = TransmonSystem(levels=levels, δ=δ) + +## let's look at the parameters of the system +sys.params + + +# Since this is a multilevel transmon and we want to implement an, let's say, $X$ gate on the qubit subspace, i.e., the first two levels we can utilize the `EmbeddedOperator` type to define the target operator. + +## define the target operator +op = EmbeddedOperator(:X, sys) + +## show the full operator +op.operator |> sparse + +# In this formulation, we also use a subspace identity as the initial state, which looks like + +function get_subspace_identity(op::EmbeddedOperator) + return embed( + Matrix{ComplexF64}(I(length(op.subspace))), + op.subspace, + size(op)[1] + ) +end +get_subspace_identity(op) |> sparse + +# We can then pass this embedded operator to the `UnitarySmoothPulseProblem` template to create the problem + +## create the problem +prob = UnitarySmoothPulseProblem(sys, op, T, Δt; a_bound=a_bound) + +## solve the problem +solve!(prob; max_iter=50) + +# Let's look at the fidelity in the subspace + +println("Fidelity: ", unitary_rollout_fidelity(prob.trajectory, sys; subspace=op.subspace)) + +# and plot the result using the `plot_unitary_populations` function. + +plot_unitary_populations(prob.trajectory; fig_size=(900, 700)) + + +# ## Leakage suppresion +# As can be seen from the above plot, there is a substantial amount of leakage into the higher levels during the evolution. To mitigate this, we have implemented a constraint to avoid populating the leakage levels, which should ideally drive those leakage populations down to zero. +# To implement this, pass `leakage_constraint=true` and set `leakage_constraint_value={value}` and `leakage_cost={value}` to the `PiccoloOptions` instance passed to the `UnitarySmoothPulseProblem` template. + +## create the a leakage suppression problem, initializing with the previous solution + +prob_leakage = UnitarySmoothPulseProblem(sys, op, T, Δt; + a_bound=a_bound, + a_guess=prob.trajectory.a[:, :], + piccolo_options=PiccoloOptions( + leakage_constraint=true, + leakage_constraint_value=1e-1, + leakage_cost=1e-1 + ) +) + +## solve the problem + +solve!(prob_leakage; max_iter=50) + +# Let's look at the fidelity in the subspace + +println("Fidelity: ", unitary_rollout_fidelity(prob_leakage.trajectory, sys; subspace=op.subspace)) + +# and plot the result using the `plot_unitary_populations` function. + +plot_unitary_populations(prob_leakage.trajectory; fig_size=(900, 700)) + +# Here we can see that the leakage populations have been driven substantially down. \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index 7875f14f..3a296bca 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -10,6 +10,7 @@ pages = [ "Home" => "index.md", "Examples" => [ "Two Qubit Gates" => "generated/examples/two_qubit_gates.md", + "Multilevel Transmon" => "generated/examples/multilevel_transmon.md", ], "Library" => [ "Ket Problem Templates" => "generated/man/ket_problem_templates.md", From 6096f7396d44551ab737fcb1bd3f0370eb39fc4a Mon Sep 17 00:00:00 2001 From: Gennadi Ryan Date: Tue, 8 Jul 2025 22:47:19 -0400 Subject: [PATCH 5/8] Updating leakage parameters; adding minimum fidelity assertions --- docs/literate/examples/multilevel_transmon.jl | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/literate/examples/multilevel_transmon.jl b/docs/literate/examples/multilevel_transmon.jl index e6edd926..ea3450ca 100644 --- a/docs/literate/examples/multilevel_transmon.jl +++ b/docs/literate/examples/multilevel_transmon.jl @@ -82,7 +82,9 @@ solve!(prob; max_iter=50) # Let's look at the fidelity in the subspace -println("Fidelity: ", unitary_rollout_fidelity(prob.trajectory, sys; subspace=op.subspace)) +fid = unitary_rollout_fidelity(prob.trajectory, sys; subspace=op.subspace) +println("Fidelity: ", fid) +@assert fid > 0.99 # and plot the result using the `plot_unitary_populations` function. @@ -100,21 +102,23 @@ prob_leakage = UnitarySmoothPulseProblem(sys, op, T, Δt; a_guess=prob.trajectory.a[:, :], piccolo_options=PiccoloOptions( leakage_constraint=true, - leakage_constraint_value=1e-1, - leakage_cost=1e-1 - ) + leakage_constraint_value=1e-2, + leakage_cost=1e-2, + ), ) ## solve the problem -solve!(prob_leakage; max_iter=50) +solve!(prob_leakage; max_iter=150) # Let's look at the fidelity in the subspace -println("Fidelity: ", unitary_rollout_fidelity(prob_leakage.trajectory, sys; subspace=op.subspace)) +fid_leakage = unitary_rollout_fidelity(prob_leakage.trajectory, sys; subspace=op.subspace) +println("Fidelity: ", fid_leakage) +@assert fid_leakage > 0.99 # and plot the result using the `plot_unitary_populations` function. plot_unitary_populations(prob_leakage.trajectory; fig_size=(900, 700)) -# Here we can see that the leakage populations have been driven substantially down. \ No newline at end of file +# Here we can see that the leakage populations have been driven substantially down. From 26fffef143b53ccd442ce29e965c5177880c9576 Mon Sep 17 00:00:00 2001 From: Gennadi Ryan Date: Tue, 8 Jul 2025 23:25:58 -0400 Subject: [PATCH 6/8] Adding additional iterations to ensure convergence when suppressing leakage --- docs/literate/examples/multilevel_transmon.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/literate/examples/multilevel_transmon.jl b/docs/literate/examples/multilevel_transmon.jl index ea3450ca..fd451ac4 100644 --- a/docs/literate/examples/multilevel_transmon.jl +++ b/docs/literate/examples/multilevel_transmon.jl @@ -109,7 +109,7 @@ prob_leakage = UnitarySmoothPulseProblem(sys, op, T, Δt; ## solve the problem -solve!(prob_leakage; max_iter=150) +solve!(prob_leakage; max_iter=300) # Let's look at the fidelity in the subspace From cadd9fda120cd16b2d69d3fac7b9a55062d40f86 Mon Sep 17 00:00:00 2001 From: Gennadi Ryan Date: Wed, 9 Jul 2025 00:14:34 -0400 Subject: [PATCH 7/8] Tweaking iteration count for solve with leakage suppression --- docs/literate/examples/multilevel_transmon.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/literate/examples/multilevel_transmon.jl b/docs/literate/examples/multilevel_transmon.jl index fd451ac4..7b3f2bdc 100644 --- a/docs/literate/examples/multilevel_transmon.jl +++ b/docs/literate/examples/multilevel_transmon.jl @@ -109,7 +109,7 @@ prob_leakage = UnitarySmoothPulseProblem(sys, op, T, Δt; ## solve the problem -solve!(prob_leakage; max_iter=300) +solve!(prob_leakage; max_iter=200) # Let's look at the fidelity in the subspace From 17337a03d2d5a421884f7d3fab2c8bbd6561fef1 Mon Sep 17 00:00:00 2001 From: Gennadi Ryan Date: Wed, 9 Jul 2025 14:47:07 -0400 Subject: [PATCH 8/8] Tweaking iteration count for solve with leakage suppression --- docs/literate/examples/multilevel_transmon.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/literate/examples/multilevel_transmon.jl b/docs/literate/examples/multilevel_transmon.jl index 7b3f2bdc..ca837510 100644 --- a/docs/literate/examples/multilevel_transmon.jl +++ b/docs/literate/examples/multilevel_transmon.jl @@ -109,7 +109,7 @@ prob_leakage = UnitarySmoothPulseProblem(sys, op, T, Δt; ## solve the problem -solve!(prob_leakage; max_iter=200) +solve!(prob_leakage; max_iter=250) # Let's look at the fidelity in the subspace