Quickstart Guide

This guide shows you how to set up and solve a quantum optimal control problem in Piccolo.jl. We'll synthesize a single-qubit X gate.

The Problem

We want to find control pulses that implement an X gate on a single qubit with system Hamiltonian:

\[H(t) = \frac{\omega}{2} \sigma_z + u_1(t) \sigma_x + u_2(t) \sigma_y\]

using Piccolo

Step 1: Define the Quantum System

First, we define our quantum system by specifying the drift Hamiltonian (always-on), the drive Hamiltonians (controllable), and the bounds on control amplitudes.

# Drift Hamiltonian: qubit frequency term
H_drift = 0.5 * PAULIS[:Z]

# Drive Hamiltonians: X and Y controls
H_drives = [PAULIS[:X], PAULIS[:Y]]

# Maximum control amplitudes
drive_bounds = [1.0, 1.0]

# Create the quantum system
sys = QuantumSystem(H_drift, H_drives, drive_bounds)
QuantumSystem: levels = 2, n_drives = 2

Step 2: Create an Initial Pulse

We need an initial guess for the control pulse. ZeroOrderPulse represents piecewise constant controls.

# Time parameters
T = 10.0   # Total gate duration
N = 100    # Number of timesteps

# Create time vector
times = collect(range(0, T, length = N))

# Random initial controls (scaled by drive bounds)
initial_controls = 0.1 * randn(2, N)

# Create the pulse
pulse = ZeroOrderPulse(initial_controls, times)
ZeroOrderPulse{DataInterpolations.ConstantInterpolation{Matrix{Float64}, Vector{Float64}, Vector{Union{}}, Float64}}(DataInterpolations.ConstantInterpolation{Matrix{Float64}, Vector{Float64}, Vector{Union{}}, Float64}([-0.19770097589972205 0.011590742519884458 … -0.026241978777701482 0.04993470949325754; -0.029018195168309918 -0.04899050687278563 … 0.032188827040722325 0.20482941245343841], [0.0, 0.10101010101010101, 0.20202020202020202, 0.30303030303030304, 0.40404040404040403, 0.5050505050505051, 0.6060606060606061, 0.7070707070707071, 0.8080808080808081, 0.9090909090909091  …  9.090909090909092, 9.191919191919192, 9.292929292929292, 9.393939393939394, 9.494949494949495, 9.595959595959595, 9.696969696969697, 9.797979797979798, 9.8989898989899, 10.0], Union{}[], nothing, :left, DataInterpolations.ExtrapolationType.None, DataInterpolations.ExtrapolationType.None, FindFirstFunctions.Guesser{Vector{Float64}}([0.0, 0.10101010101010101, 0.20202020202020202, 0.30303030303030304, 0.40404040404040403, 0.5050505050505051, 0.6060606060606061, 0.7070707070707071, 0.8080808080808081, 0.9090909090909091  …  9.090909090909092, 9.191919191919192, 9.292929292929292, 9.393939393939394, 9.494949494949495, 9.595959595959595, 9.696969696969697, 9.797979797979798, 9.8989898989899, 10.0], Base.RefValue{Int64}(1), true), false, true), 10.0, 2, :u, [0.0, 0.0], [0.0, 0.0])

Step 3: Define the Goal via a Trajectory

A UnitaryTrajectory combines the system, pulse, and target gate.

# Target: X gate
U_goal = GATES[:X]

# Create the trajectory
qtraj = UnitaryTrajectory(sys, pulse, U_goal)
UnitaryTrajectory{ZeroOrderPulse{DataInterpolations.ConstantInterpolation{Matrix{Float64}, Vector{Float64}, Vector{Union{}}, Float64}}, SciMLBase.ODESolution{ComplexF64, 3, Vector{Matrix{ComplexF64}}, Nothing, Nothing, Vector{Float64}, Vector{Vector{Matrix{ComplexF64}}}, Nothing, SciMLBase.ODEProblem{Matrix{ComplexF64}, Tuple{Float64, Float64}, true, SciMLBase.NullParameters, SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Base.Pairs{Symbol, Vector{Float64}, Nothing, @NamedTuple{tstops::Vector{Float64}}}, SciMLBase.StandardODEProblem}, OrdinaryDiffEqLinear.MagnusAdapt4, OrdinaryDiffEqCore.InterpolationData{SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Vector{Matrix{ComplexF64}}, Vector{Float64}, Vector{Vector{Matrix{ComplexF64}}}, Nothing, OrdinaryDiffEqLinear.MagnusAdapt4Cache{Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Nothing}, Nothing}, SciMLBase.DEStats, Nothing, Nothing, Nothing, Nothing}, Matrix{ComplexF64}}(QuantumSystem: levels = 2, n_drives = 2, ZeroOrderPulse{DataInterpolations.ConstantInterpolation{Matrix{Float64}, Vector{Float64}, Vector{Union{}}, Float64}}(DataInterpolations.ConstantInterpolation{Matrix{Float64}, Vector{Float64}, Vector{Union{}}, Float64}([-0.19770097589972205 0.011590742519884458 … -0.026241978777701482 0.04993470949325754; -0.029018195168309918 -0.04899050687278563 … 0.032188827040722325 0.20482941245343841], [0.0, 0.10101010101010101, 0.20202020202020202, 0.30303030303030304, 0.40404040404040403, 0.5050505050505051, 0.6060606060606061, 0.7070707070707071, 0.8080808080808081, 0.9090909090909091  …  9.090909090909092, 9.191919191919192, 9.292929292929292, 9.393939393939394, 9.494949494949495, 9.595959595959595, 9.696969696969697, 9.797979797979798, 9.8989898989899, 10.0], Union{}[], nothing, :left, DataInterpolations.ExtrapolationType.None, DataInterpolations.ExtrapolationType.None, FindFirstFunctions.Guesser{Vector{Float64}}([0.0, 0.10101010101010101, 0.20202020202020202, 0.30303030303030304, 0.40404040404040403, 0.5050505050505051, 0.6060606060606061, 0.7070707070707071, 0.8080808080808081, 0.9090909090909091  …  9.090909090909092, 9.191919191919192, 9.292929292929292, 9.393939393939394, 9.494949494949495, 9.595959595959595, 9.696969696969697, 9.797979797979798, 9.8989898989899, 10.0], Base.RefValue{Int64}(100), true), false, true), 10.0, 2, :u, [0.0, 0.0], [0.0, 0.0]), ComplexF64[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im], ComplexF64[0.0 + 0.0im 1.0 + 0.0im; 1.0 + 0.0im 0.0 + 0.0im], SciMLBase.ODESolution{ComplexF64, 3, Vector{Matrix{ComplexF64}}, Nothing, Nothing, Vector{Float64}, Vector{Vector{Matrix{ComplexF64}}}, Nothing, SciMLBase.ODEProblem{Matrix{ComplexF64}, Tuple{Float64, Float64}, true, SciMLBase.NullParameters, SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Base.Pairs{Symbol, Vector{Float64}, Nothing, @NamedTuple{tstops::Vector{Float64}}}, SciMLBase.StandardODEProblem}, OrdinaryDiffEqLinear.MagnusAdapt4, OrdinaryDiffEqCore.InterpolationData{SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Vector{Matrix{ComplexF64}}, Vector{Float64}, Vector{Vector{Matrix{ComplexF64}}}, Nothing, OrdinaryDiffEqLinear.MagnusAdapt4Cache{Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Nothing}, Nothing}, SciMLBase.DEStats, Nothing, Nothing, Nothing, Nothing}(Matrix{ComplexF64}[[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im], [0.9985507115505804 - 0.049975842857885096im 0.002900417523501793 + 0.01976054580883007im; -0.002900417523501794 + 0.019760545808830077im 0.9985507115505803 + 0.04997584285788509im], [0.9947973767169338 - 0.09971897507199891im 0.008812316409221893 + 0.018885136144634548im; -0.008812316409221897 + 0.018885136144634548im 0.9947973767169335 + 0.0997189750719989im], [0.9880895249812404 - 0.14977461131173617im -0.010122261953384231 + 0.033825969930123864im; 0.01012226195338423 + 0.03382596993012388im 0.9880895249812405 + 0.1497746113117362im], [0.9795380703277546 - 0.19957696166253816im -0.019779125141192393 + 0.016822347065102602im; 0.019779125141192386 + 0.016822347065102616im 0.9795380703277549 + 0.19957696166253827im], [0.9680901288604803 - 0.24841956141838087im -0.028618197049137928 + 0.016438452033418142im; 0.028618197049137928 + 0.016438452033418174im 0.9680901288604814 + 0.24841956141838117im], [0.9548522916111278 - 0.2965889132064046im -0.0138227314534196 + 0.010052356101332894im; 0.013822731453419605 + 0.01005235610133293im 0.954852291611129 + 0.296588913206405im], [0.9384157297107518 - 0.3440627481606418im -0.031158328337467595 + 0.0050894139936072495im; 0.031158328337467574 + 0.005089413993607297im 0.938415729710753 + 0.34406274816064225im], [0.9198612276479058 - 0.39076367512714544im -0.03401131267807349 - 0.0015174587730290299im; 0.03401131267807344 - 0.0015174587730289709im 0.9198612276479069 + 0.3907636751271458im], [0.898932690659662 - 0.43652463368749356im -0.03552459178840864 - 0.010211034504197941im; 0.03552459178840857 - 0.010211034504197875im 0.8989326906596626 + 0.4365246336874938im]  …  [-0.17553062954753118 + 0.9597406722719514im 0.18771429635814876 - 0.11335864775306048im; -0.187714296358149 - 0.11335864775306052im -0.1755306295475295 - 0.9597406722719554im], [-0.1264622448002832 + 0.9683315811290104im 0.1809188844013394 - 0.11666021984912495im; -0.18091888440133957 - 0.11666021984912493im -0.1264622448002813 - 0.9683315811290136im], [-0.08208026858982409 + 0.9753280912284829im 0.1551306796717597 - 0.13391197180764175im; -0.1551306796717599 - 0.1339119718076416im -0.08208026858982206 - 0.9753280912284864im], [-0.032040879321861004 + 0.9755788135867433im 0.16074242122233715 - 0.14622323533745168im; -0.16074242122233726 - 0.14622323533745152im -0.03204087932185882 - 0.9755788135867466im], [0.018730122858056437 + 0.9754149153573765im 0.16100262461274753 - 0.1493086744429084im; -0.1610026246127475 - 0.1493086744429082im 0.01873012285805877 - 0.9754149153573789im], [0.06631764297161888 + 0.9759053248803423im 0.14089812447857372 - 0.15283483117179167im; -0.14089812447857375 - 0.15283483117179145im 0.06631764297162134 - 0.9759053248803446im], [0.1146657124919075 + 0.9717834028085809im 0.1305525048089278 - 0.15951437519113898im; -0.13055250480892786 - 0.15951437519113884im 0.11466571249191015 - 0.9717834028085836im], [0.16196027596370674 + 0.967208298726967im 0.11033988836472247 - 0.1615613967478452im; -0.11033988836472253 - 0.16156139674784506im 0.1619602759637095 - 0.9672082987269693im], [0.21006722280917137 + 0.9602163727160283im 0.09378462754264098 - 0.15830578986888094im; -0.09378462754264116 - 0.15830578986888086im 0.21006722280917436 - 0.9602163727160311im], [0.25851090814435507 + 0.9487763430584681im 0.08758421906895261 - 0.15913694037862183im; -0.08758421906895278 - 0.15913694037862164im 0.2585109081443581 - 0.9487763430584705im]], nothing, nothing, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9  …  9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0], Vector{Matrix{ComplexF64}}[[[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im]]], nothing, SciMLBase.ODEProblem{Matrix{ComplexF64}, Tuple{Float64, Float64}, true, SciMLBase.NullParameters, SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Base.Pairs{Symbol, Vector{Float64}, Nothing, @NamedTuple{tstops::Vector{Float64}}}, SciMLBase.StandardODEProblem}(SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}(MatrixOperator(2 × 2), LinearAlgebra.UniformScaling{Bool}(true), nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, SciMLBase.DEFAULT_OBSERVED, nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}(Dict{Symbol, Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}(:U => CartesianIndices((2, 2)), :U_2_2 => CartesianIndex(2, 2), :U_1_1 => CartesianIndex(1, 1), :U_2_1 => CartesianIndex(2, 1), :U_1_2 => CartesianIndex(1, 2)), :t, Dict{Symbol, Float64}()), nothing, nothing), ComplexF64[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im], (0.0, 10.0), SciMLBase.NullParameters(), Base.Pairs(:tstops => [0.0, 0.1, 0.10101010101010101, 0.2, 0.20202020202020202, 0.3, 0.30303030303030304, 0.4, 0.40404040404040403, 0.5  …  9.5, 9.595959595959595, 9.6, 9.696969696969697, 9.7, 9.797979797979798, 9.8, 9.8989898989899, 9.9, 10.0]), SciMLBase.StandardODEProblem()), OrdinaryDiffEqLinear.MagnusAdapt4(), OrdinaryDiffEqCore.InterpolationData{SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Vector{Matrix{ComplexF64}}, Vector{Float64}, Vector{Vector{Matrix{ComplexF64}}}, Nothing, OrdinaryDiffEqLinear.MagnusAdapt4Cache{Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Nothing}, Nothing}(SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}(MatrixOperator(2 × 2), LinearAlgebra.UniformScaling{Bool}(true), nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, SciMLBase.DEFAULT_OBSERVED, nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}(Dict{Symbol, Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}(:U => CartesianIndices((2, 2)), :U_2_2 => CartesianIndex(2, 2), :U_1_1 => CartesianIndex(1, 1), :U_2_1 => CartesianIndex(2, 1), :U_1_2 => CartesianIndex(1, 2)), :t, Dict{Symbol, Float64}()), nothing, nothing), Matrix{ComplexF64}[[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im], [0.9985507115505804 - 0.049975842857885096im 0.002900417523501793 + 0.01976054580883007im; -0.002900417523501794 + 0.019760545808830077im 0.9985507115505803 + 0.04997584285788509im], [0.9947973767169338 - 0.09971897507199891im 0.008812316409221893 + 0.018885136144634548im; -0.008812316409221897 + 0.018885136144634548im 0.9947973767169335 + 0.0997189750719989im], [0.9880895249812404 - 0.14977461131173617im -0.010122261953384231 + 0.033825969930123864im; 0.01012226195338423 + 0.03382596993012388im 0.9880895249812405 + 0.1497746113117362im], [0.9795380703277546 - 0.19957696166253816im -0.019779125141192393 + 0.016822347065102602im; 0.019779125141192386 + 0.016822347065102616im 0.9795380703277549 + 0.19957696166253827im], [0.9680901288604803 - 0.24841956141838087im -0.028618197049137928 + 0.016438452033418142im; 0.028618197049137928 + 0.016438452033418174im 0.9680901288604814 + 0.24841956141838117im], [0.9548522916111278 - 0.2965889132064046im -0.0138227314534196 + 0.010052356101332894im; 0.013822731453419605 + 0.01005235610133293im 0.954852291611129 + 0.296588913206405im], [0.9384157297107518 - 0.3440627481606418im -0.031158328337467595 + 0.0050894139936072495im; 0.031158328337467574 + 0.005089413993607297im 0.938415729710753 + 0.34406274816064225im], [0.9198612276479058 - 0.39076367512714544im -0.03401131267807349 - 0.0015174587730290299im; 0.03401131267807344 - 0.0015174587730289709im 0.9198612276479069 + 0.3907636751271458im], [0.898932690659662 - 0.43652463368749356im -0.03552459178840864 - 0.010211034504197941im; 0.03552459178840857 - 0.010211034504197875im 0.8989326906596626 + 0.4365246336874938im]  …  [-0.17553062954753118 + 0.9597406722719514im 0.18771429635814876 - 0.11335864775306048im; -0.187714296358149 - 0.11335864775306052im -0.1755306295475295 - 0.9597406722719554im], [-0.1264622448002832 + 0.9683315811290104im 0.1809188844013394 - 0.11666021984912495im; -0.18091888440133957 - 0.11666021984912493im -0.1264622448002813 - 0.9683315811290136im], [-0.08208026858982409 + 0.9753280912284829im 0.1551306796717597 - 0.13391197180764175im; -0.1551306796717599 - 0.1339119718076416im -0.08208026858982206 - 0.9753280912284864im], [-0.032040879321861004 + 0.9755788135867433im 0.16074242122233715 - 0.14622323533745168im; -0.16074242122233726 - 0.14622323533745152im -0.03204087932185882 - 0.9755788135867466im], [0.018730122858056437 + 0.9754149153573765im 0.16100262461274753 - 0.1493086744429084im; -0.1610026246127475 - 0.1493086744429082im 0.01873012285805877 - 0.9754149153573789im], [0.06631764297161888 + 0.9759053248803423im 0.14089812447857372 - 0.15283483117179167im; -0.14089812447857375 - 0.15283483117179145im 0.06631764297162134 - 0.9759053248803446im], [0.1146657124919075 + 0.9717834028085809im 0.1305525048089278 - 0.15951437519113898im; -0.13055250480892786 - 0.15951437519113884im 0.11466571249191015 - 0.9717834028085836im], [0.16196027596370674 + 0.967208298726967im 0.11033988836472247 - 0.1615613967478452im; -0.11033988836472253 - 0.16156139674784506im 0.1619602759637095 - 0.9672082987269693im], [0.21006722280917137 + 0.9602163727160283im 0.09378462754264098 - 0.15830578986888094im; -0.09378462754264116 - 0.15830578986888086im 0.21006722280917436 - 0.9602163727160311im], [0.25851090814435507 + 0.9487763430584681im 0.08758421906895261 - 0.15913694037862183im; -0.08758421906895278 - 0.15913694037862164im 0.2585109081443581 - 0.9487763430584705im]], [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9  …  9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0], Vector{Matrix{ComplexF64}}[[[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im]]], nothing, false, OrdinaryDiffEqLinear.MagnusAdapt4Cache{Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Nothing}(ComplexF64[0.25851090814435507 + 0.9487763430584681im 0.08758421906895261 - 0.15913694037862183im; -0.08758421906895278 - 0.15913694037862164im 0.2585109081443581 - 0.9487763430584705im], ComplexF64[0.258182766162708 + 0.9488585027903967im 0.08764037967888662 - 0.15914887617789295im; -0.08764037967888678 - 0.15914887617789275im 0.2581827661627111 - 0.9488585027903991im], ComplexF64[0.258182766162708 + 0.9488585027903967im 0.08764037967888662 - 0.15914887617789295im; -0.08764037967888678 - 0.15914887617789275im 0.2581827661627111 - 0.9488585027903991im], ComplexF64[2.0e-8 + 0.0im 1.0e-8 + 0.0im; 1.0e-8 + 0.0im 2.0e-8 + 0.0im], ComplexF64[0.48142667384962057 - 0.12626842441594155im -0.06298511380058598 - 0.006502320936594287im; 0.06298511380058584 - 0.006502320936594523im 0.48142667384962173 + 0.12626842441594305im], ComplexF64[0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im], ComplexF64[0.4843815387738686 - 0.09228603553938461im -0.17989597868202456 + 0.13763652426488543im; 0.17989597868202373 + 0.13763652426488499im 0.4843815387738697 + 0.09228603553938612im], ComplexF64[0.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 0.0 + 0.0im], ComplexF64[-0.04071782474992763 - 0.001166270416314783im -0.4785869922571024 - 0.38608845785970664im; 0.4785869922571024 - 0.38608845785970664im -0.04071782474992756 + 0.0011662704163147813im], nothing), nothing, false), false, 0, SciMLBase.DEStats(1912, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1192, 717, 0.0), nothing, SciMLBase.ReturnCode.Success, nothing, nothing, nothing))

Step 4: Set Up the Optimization Problem

SmoothPulseProblem creates the optimization problem with:

  • Fidelity objective (weight Q)
  • Regularization for smooth controls (weight R)
  • Derivative bounds for control smoothness
qcp = SmoothPulseProblem(
    qtraj,
    N;
    Q = 100.0,       # Fidelity weight
    R = 1e-2,        # Regularization weight
    ddu_bound = 1.0,  # Control acceleration bound
)
QuantumControlProblem{UnitaryTrajectory{ZeroOrderPulse{DataInterpolations.ConstantInterpolation{Matrix{Float64}, Vector{Float64}, Vector{Union{}}, Float64}}, SciMLBase.ODESolution{ComplexF64, 3, Vector{Matrix{ComplexF64}}, Nothing, Nothing, Vector{Float64}, Vector{Vector{Matrix{ComplexF64}}}, Nothing, SciMLBase.ODEProblem{Matrix{ComplexF64}, Tuple{Float64, Float64}, true, SciMLBase.NullParameters, SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Base.Pairs{Symbol, Vector{Float64}, Nothing, @NamedTuple{tstops::Vector{Float64}}}, SciMLBase.StandardODEProblem}, OrdinaryDiffEqLinear.MagnusAdapt4, OrdinaryDiffEqCore.InterpolationData{SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Vector{Matrix{ComplexF64}}, Vector{Float64}, Vector{Vector{Matrix{ComplexF64}}}, Nothing, OrdinaryDiffEqLinear.MagnusAdapt4Cache{Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Nothing}, Nothing}, SciMLBase.DEStats, Nothing, Nothing, Nothing, Nothing}, Matrix{ComplexF64}}}
  System: QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}
  Goal: Matrix{ComplexF64}
  Trajectory: 100 knots
  State: Ũ⃗
  Controls: u

Step 5: Solve!

solve!(qcp; max_iter = 20, verbose = false, print_level = 1)

Step 6: Analyze Results

After solving, we can check the fidelity and examine the optimized controls.

# Check final fidelity
fidelity(qcp)
0.9999995867273045

Access the trajectory and check the final unitary:

traj = get_trajectory(qcp)
U_final = iso_vec_to_operator(traj[:Ũ⃗][:, end])
round.(U_final, digits = 3)
2×2 Matrix{ComplexF64}:
    0.0+0.0im  0.001-1.0im
 -0.001-1.0im    0.0-0.0im

Visualization

Piccolo provides specialized plotting functions for quantum trajectories:

using CairoMakie

# Plot the unitary evolution (state populations over time)
fig = plot_unitary_populations(traj)
Example block output

Minimum Time Optimization

Now let's find the shortest gate duration that achieves 99% fidelity.

First, we need to create a new problem with variable timesteps enabled:

# Create problem with free-time optimization
qcp_free = SmoothPulseProblem(
    qtraj,
    N;
    Q = 100.0,
    R = 1e-2,
    ddu_bound = 1.0,
    Δt_bounds = (0.01, 0.5),  # Enable variable timesteps
)
solve!(
    qcp_free;
    max_iter = 20,
    verbose = false,
    print_level = 1,
)

# Convert to minimum time problem
qcp_mintime = MinimumTimeProblem(qcp_free; final_fidelity = 0.99)
solve!(
    qcp_mintime;
    max_iter = 20,
    verbose = false,
    print_level = 1,
)
    constructing SmoothPulseProblem for UnitaryTrajectory...
	applying timesteps_all_equal constraint: Δt
    constructing MinimumTimeProblem from QuantumControlProblem{UnitaryTrajectory{ZeroOrderPulse{DataInterpolations.ConstantInterpolation{Matrix{Float64}, Vector{Float64}, Vector{Union{}}, Float64}}, SciMLBase.ODESolution{ComplexF64, 3, Vector{Matrix{ComplexF64}}, Nothing, Nothing, Vector{Float64}, Vector{Vector{Matrix{ComplexF64}}}, Nothing, SciMLBase.ODEProblem{Matrix{ComplexF64}, Tuple{Float64, Float64}, true, SciMLBase.NullParameters, SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Base.Pairs{Symbol, Vector{Float64}, Nothing, @NamedTuple{tstops::Vector{Float64}}}, SciMLBase.StandardODEProblem}, OrdinaryDiffEqLinear.MagnusAdapt4, OrdinaryDiffEqCore.InterpolationData{SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#37#38"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.QuantumSystems.var"#39#40"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}, Vector{DriftTerm{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Returns{Float64}, Returns{Float64}}}, SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Vector{Matrix{ComplexF64}}, Vector{Float64}, Vector{Vector{Matrix{ComplexF64}}}, Nothing, OrdinaryDiffEqLinear.MagnusAdapt4Cache{Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Nothing}, Nothing}, SciMLBase.DEStats, Nothing, Nothing, Nothing, Nothing}, Matrix{ComplexF64}}}...
	final fidelity constraint: 0.99
	minimum-time weight D: 100.0

Compare durations:

initial_duration = sum(get_timesteps(get_trajectory(qcp_free)))
minimum_duration = sum(get_timesteps(get_trajectory(qcp_mintime)))

initial_duration
12.429085117242698
minimum_duration
5.605073009405118
fidelity(qcp_mintime)
0.9908208074426424

Plot the time-optimal solution:

fig_mintime = plot_unitary_populations(get_trajectory(qcp_mintime))
Example block output

State Preparation

Instead of synthesizing a full unitary gate, you can prepare a specific quantum state using KetTrajectory:

ψ_init = ComplexF64[1.0, 0.0]  # |0⟩
ψ_goal = ComplexF64[0.0, 1.0]  # |1⟩
qcp_state = SmoothPulseProblem(KetTrajectory(sys, pulse, ψ_init, ψ_goal), N)
solve!(
    qcp_state;
    max_iter = 20,
    verbose = false,
    print_level = 1,
)
fidelity(qcp_state)
0.994225519370145

Robust Control

To optimize a pulse that works across parameter variations (e.g., uncertain qubit frequency), use SamplingProblem:

# Perturbed systems: ±10% drift Hamiltonian
sys_low = QuantumSystem(0.9 * H_drift, H_drives, drive_bounds)
sys_high = QuantumSystem(1.1 * H_drift, H_drives, drive_bounds)

# Start from a nominal solution, then add robustness
qcp_robust = SamplingProblem(qcp, [sys_low, sys, sys_high])
solve!(
    qcp_robust;
    max_iter = 20,
    verbose = false,
    print_level = 1,
)
fidelity(qcp_robust)
3-element Vector{Float64}:
 0.9970676593183584
 0.9999785687241922
 0.9971921002966301

Next Steps


This page was generated using Literate.jl.