Quantum Systems

Piccolo.jl models quantum control using drive-based Hamiltonians:

\[H(\boldsymbol{u}, t) = H_{\text{drift}} + \sum_{d} c_d(\boldsymbol{u})\, H_d\]

where $H_{\text{drift}}$ is the always-on Hamiltonian, $\{H_d\}$ are the drive operators, and $c_d(\boldsymbol{u})$ is a scalar coefficient for each drive. For standard bilinear control, $c_d = u_i$ (LinearDrive); Piccolo.jl also supports NonlinearDrive terms (e.g., $c_d = u_1^2 + u_2^2$) for displaced-frame and cross-Kerr physics.

For optimization, the Hamiltonian is converted to a generator:

\[G(\boldsymbol{u}) = -i\!\left( H_{\text{drift}} + \sum_{d} c_d(\boldsymbol{u})\, H_d \right)\]

so that $\dot{\psi} = G\,\psi$ (ket) or $\dot{U} = G\,U$ (unitary propagator). For open systems, the Lindbladian superoperator $\mathcal{G}(\boldsymbol{u})$ has the same bilinear structure (see Isomorphisms).

System Types

TypeDynamicsUse Case
QuantumSystem$\dot{U} = G\,U$Closed systems, gate synthesis
OpenQuantumSystem$\dot{\vec\rho} = \mathcal{G}\,\vec\rho$Dissipative systems (Lindblad)
CompositeQuantumSystem$\mathcal{H} = \mathcal{H}_1 \otimes \mathcal{H}_2$Multi-subsystem setups

Platform Templates

Each page below documents the physical Hamiltonian, constructor API, and a worked optimization example.

PlatformTemplate(s)System TypeKey Physics
Transmon QubitsTransmonSystem, MultiTransmonSystem, TransmonCavitySystemQuantumSystem / CompositeQuantumSystemAnharmonicity, dipole coupling, dispersive readout
Trapped IonsIonChainSystem, RadialMSGateSystemQuantumSystemMotional modes, Lamb-Dicke coupling, Mølmer-Sørensen gates
Rydberg AtomsRydbergChainSystemQuantumSystemVan der Waals blockade, global/local drives
Cat QubitsCatSystemOpenQuantumSystemTwo-photon drive, Kerr nonlinearity, photon loss
Silicon Spins(coming soon)QuantumSystemExchange-only qubits, detuning control

Construction

All templates produce a QuantumSystem (or subtype) that plugs directly into Trajectories and Problem Templates:

using Piccolo

sys = TransmonSystem(levels=3, δ=0.2, drive_bounds=[0.2, 0.2])
pulse = ZeroOrderPulse(0.05 * randn(2, 100), collect(range(0, 10, 100)))
qtraj = UnitaryTrajectory(sys, pulse, GATES[:X])
qcp = SmoothPulseProblem(qtraj, 100; Q=100.0)
solve!(qcp)

Custom Systems

For platforms not covered by a template, build directly from matrices:

using Piccolo
using SparseArrays

# Standard linear drives: H(u) = H_drift + u₁ H₁ + u₂ H₂
H_drift = PAULIS[:Z]
H_drives = [PAULIS[:X], PAULIS[:Y]]
drive_bounds = [1.0, 1.0]

sys = QuantumSystem(H_drift, H_drives, drive_bounds)
QuantumSystem: levels = 2, n_drives = 2

For systems with nonlinear drive coefficients, use typed drive terms. The Jacobian is auto-generated via ForwardDiff:

# H(u) = u₁ σx + u₂ σy + (u₁² + u₂²) σz
drives = AbstractDrive[
    LinearDrive(sparse(ComplexF64.(PAULIS[:X])), 1),
    LinearDrive(sparse(ComplexF64.(PAULIS[:Y])), 2),
    NonlinearDrive(PAULIS[:Z], u -> u[1]^2 + u[2]^2),   # auto-Jacobian
]
sys = QuantumSystem(H_drift, drives, [1.0, 1.0])
QuantumSystem: levels = 2, n_drives = 2

You can also provide a hand-written Jacobian (validated against ForwardDiff at construction):

NonlinearDrive(PAULIS[:Z],
    u -> u[1]^2 + u[2]^2,                         # coefficient c(u)
    (u, j) -> j == 1 ? 2u[1] : j == 2 ? 2u[2] : 0.0;  # Jacobian ∂c/∂uⱼ
    active_controls = [1, 2]                       # structural sparsity hint
)
NonlinearDrive{Main.var"#6#7", Main.var"#8#9"}(sparse([1, 2], [1, 2], ComplexF64[1.0 + 0.0im, -1.0 + 0.0im], 2, 2), Main.var"#6#7"(), Main.var"#8#9"(), [1, 2])

All Hamiltonians must be Hermitian ($H = H^\dagger$); Piccolo.jl validates this at construction.

See Also