Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -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"
124 changes: 124 additions & 0 deletions docs/literate/examples/multilevel_transmon.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# # 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

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.

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-2,
leakage_cost=1e-2,
),
)

## solve the problem

solve!(prob_leakage; max_iter=250)

# Let's look at the fidelity in the 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.
13 changes: 7 additions & 6 deletions docs/literate/examples/two_qubit_gates.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ using PiccoloQuantumObjects
using NamedTrajectories
using LinearAlgebra

# `using PiccoloPlots`
# `using CairoMakie`
using PiccoloPlots
using CairoMakie

⊗(a, b) = kron(a, b)

Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -183,7 +184,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

Expand All @@ -193,7 +194,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:

Expand Down
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading