Multilevel Transmon
In this example we will look at a multilevel transmon qubit with a Hamiltonian given by
\[\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:
\[\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 Piccolo
using SparseArrays
using Random;
Random.seed!(123);
# 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
dda_bound = 1.0
# create the system
sys = TransmonSystem(levels = levels, δ = δ)
# let's look at the parameters of the system
sys.params
<< @example-block not executed in draft mode >>
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
<< @example-block not executed in draft mode >>
We can then pass this embedded operator to the UnitarySmoothPulseProblem
template to create
# create the problem
prob = UnitarySmoothPulseProblem(sys, op, T, Δt; a_bound = a_bound, dda_bound = dda_bound)
# solve the problem
solve!(prob; max_iter = 50)
<< @example-block not executed in draft mode >>
Let's look at the fidelity in the subspace
println(
"Fidelity: ",
unitary_rollout_fidelity(prob.trajectory, sys; subspace = op.subspace),
)
<< @example-block not executed in draft mode >>
and plot the result using the plot_unitary_populations
function.
plot_unitary_populations(prob.trajectory)
<< @example-block not executed in draft mode >>
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 the ability to add a cost to populating the leakage levels, in particular this is an $L_1$ norm cost, which is implemented via slack variables and should ideally drive those leakage populations down to zero. To implement this, pass leakage_suppresion=true
and R_leakage={value}
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,
dda_bound = dda_bound,
leakage_suppression = true,
R_leakage = 1e-1,
a_guess = prob.trajectory.a,
)
# solve the problem
solve!(prob_leakage; max_iter = 50)
<< @example-block not executed in draft mode >>
Let's look at the fidelity in the subspace
println(
"Fidelity: ",
unitary_rollout_fidelity(prob_leakage.trajectory, sys; subspace = op.subspace),
)
<< @example-block not executed in draft mode >>
and plot the result using the plot_unitary_populations
function from PiccoloPlots.jl
plot_unitary_populations(prob_leakage.trajectory)
<< @example-block not executed in draft mode >>
Here we can see that the leakage populations have been driven substantially down.
This page was generated using Literate.jl.