Quantum Systems

using PiccoloQuantumObjects
using SparseArrays # for visualization
⊗ = kron;

Quantum Systems

The QuantumSystem type is used to represent a quantum system with a drift Hamiltonian and a set of drive Hamiltonians,

\[H(u, t) = H_{\text{drift}} + \sum_i u_i H_{\text{drives}}^{(i)}\]

where $u$ is the control vector and $t$ is time.

PiccoloQuantumObjects.QuantumSystems.QuantumSystemType
QuantumSystem <: AbstractQuantumSystem

A struct for storing quantum dynamics.

Fields

  • H::Function: The Hamiltonian function: (u, t) -> H(u, t), where u is the control vector and t is time
  • G::Function: The isomorphic generator function: (u, t) -> G(u, t), including the Hamiltonian mapped to superoperator space
  • H_drift::SparseMatrixCSC{ComplexF64, Int}: The drift Hamiltonian (time-independent component)
  • H_drives::Vector{SparseMatrixCSC{ComplexF64, Int}}: The drive Hamiltonians (control-dependent components)
  • drive_bounds::Vector{Tuple{Float64, Float64}}: Drive amplitude bounds for each control (lower, upper)
  • n_drives::Int: The number of control drives in the system
  • levels::Int: The number of levels (dimension) in the system
  • time_dependent::Bool: Whether the Hamiltonian has explicit time dependence beyond control modulation
  • global_params::NamedTuple: Global parameters that the Hamiltonian may depend on (e.g., (δ=0.5, Ω=1.0))

See also OpenQuantumSystem, VariationalQuantumSystem.

source

QuantumSystem's are containers for quantum dynamics. Internally, they compute the necessary isomorphisms to perform the dynamics in a real vector space. All systems require explicit specification of drive_bounds (control bounds).

H_drift = PAULIS[:Z]
H_drives = [PAULIS[:X], PAULIS[:Y]]
drive_bounds = [(-1.0, 1.0), (-1.0, 1.0)]
system = QuantumSystem(H_drift, H_drives, drive_bounds)

u_controls = [1.0, 0.0]
t = 0.0
system.H(u_controls, t)
2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:
 1.0+0.0im   1.0+0.0im
 1.0+0.0im  -1.0+0.0im

To extract the drift and drive Hamiltonians from a QuantumSystem, use the get_drift and get_drives functions.

get_drift(system) |> sparse
2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:
 1.0+0.0im       ⋅    
     ⋅      -1.0+0.0im

Get the X drive.

drives = get_drives(system)
drives[1] |> sparse
2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:
     ⋅      1.0+0.0im
 1.0+0.0im      ⋅    

And the Y drive.

drives[2] |> sparse
2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:
     ⋅      0.0-1.0im
 0.0+1.0im      ⋅    
Note

We can also construct a QuantumSystem directly from a Hamiltonian function. The function must accept (u, t) arguments where u is the control vector and t is time.

H(u, t) = PAULIS[:Z] + u[1] * PAULIS[:X] + u[2] * PAULIS[:Y]
system = QuantumSystem(H, [(-1.0, 1.0), (-1.0, 1.0)]; time_dependent=true)
system.H([1.0, 0.0], 0.0) |> sparse
2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:
 1.0+0.0im   1.0+0.0im
 1.0+0.0im  -1.0+0.0im

Reachability tests

Whether a quantum system can be used to reach a target state or operator can be tested by computing the dynamical Lie algebra. Access to this calculation is provided by the is_reachable function.

PiccoloQuantumObjects.QuantumSystemUtils.is_reachableFunction
is_reachable(gate, hamiltonians; kwargs...)

Check if the gate is reachable using the given hamiltonians.

Arguments

  • gate::AbstractMatrix: target gate
  • hamiltonians::AbstractVector{<:AbstractMatrix}: generators of the Lie algebra

Keyword Arguments

  • subspace::AbstractVector{<:Int}=1:size(gate, 1): subspace indices
  • compute_basis::Bool=true: compute the basis or use the Hamiltonians directly
  • remove_trace::Bool=true: remove trace from generators
  • verbose::Bool=true: print information about the operator algebra
  • atol::Float32=eps(Float32): absolute tolerance

See also QuantumSystemUtils.operator_algebra.

source
is_reachable(gate::AbstractMatrix{<:Number}, system::AbstractQuantumSystem; kwargs...)

Check if the gate is reachable using the given system.

Keyword Arguments

  • use_drift::Bool=true: include drift Hamiltonian in the generators
  • kwargs...: keyword arguments for is_reachable
source

Y can be reached by commuting Z and X.

system = QuantumSystem(PAULIS[:Z], [PAULIS[:X]], [(-1.0, 1.0)])
is_reachable(PAULIS[:Y], system)
true

Y cannot be reached by X alone.

system = QuantumSystem([PAULIS[:X]], [(-1.0, 1.0)])
is_reachable(PAULIS[:Y], system)
false

Direct sums

The direct sum of two quantum systems is constructed with the direct_sum function.

PiccoloQuantumObjects.DirectSums.direct_sumFunction
direct_sum(A::AbstractMatrix, B::AbstractMatrix)

Returns the direct sum of two matrices.

source
direct_sum(A::SparseMatrixCSC, B::SparseMatrixCSC)

Returns the direct sum of two sparse matrices.

source
direct_sum(Ã⃗::AbstractVector, B̃⃗::AbstractVector)

Returns the direct sum of two iso_vec operators.

source
direct_sum(sys1::QuantumSystem, sys2::QuantumSystem)

Returns the direct sum of two QuantumSystem objects.

Constructs a new system where the Hilbert space is the direct sum of the two input systems: H = H₁ ⊕ H₂ = [H₁ 0 ] [0 H₂]

Both systems must have the same number of drives. The resulting system uses sys1's drive_bounds.

Example

sys1 = QuantumSystem([PAULIS[:X]], [(-1.0, 1.0)])
sys2 = QuantumSystem([PAULIS[:Y]], [(-1.0, 1.0)])
sys_combined = direct_sum(sys1, sys2)
source

Create a pair of non-interacting qubits.

system_1 = QuantumSystem(PAULIS[:Z], [PAULIS[:X], PAULIS[:Y]], [(-1.0, 1.0), (-1.0, 1.0)])
system_2 = QuantumSystem(PAULIS[:Z], [PAULIS[:X], PAULIS[:Y]], [(-1.0, 1.0), (-1.0, 1.0)])
system = direct_sum(system_1, system_2)
get_drift(system) |> sparse
4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:
 1.0+0.0im       ⋅          ⋅           ⋅    
     ⋅      -1.0+0.0im      ⋅           ⋅    
     ⋅           ⋅      1.0+0.0im       ⋅    
     ⋅           ⋅          ⋅      -1.0+0.0im

This page was generated using Literate.jl.