diff --git a/src/PiccoloQuantumObjects.jl b/src/PiccoloQuantumObjects.jl index a78340e..903825c 100644 --- a/src/PiccoloQuantumObjects.jl +++ b/src/PiccoloQuantumObjects.jl @@ -23,7 +23,4 @@ include("embedded_operators.jl") include("quantum_system_utils.jl") @reexport using .QuantumSystemUtils -include("quantum_system_templates/_quantum_system_templates.jl") -@reexport using .QuantumSystemTemplates - end diff --git a/src/quantum_system_templates/_quantum_system_templates.jl b/src/quantum_system_templates/_quantum_system_templates.jl deleted file mode 100644 index 0c2af67..0000000 --- a/src/quantum_system_templates/_quantum_system_templates.jl +++ /dev/null @@ -1,13 +0,0 @@ -module QuantumSystemTemplates - -using ..QuantumSystems -using ..QuantumObjectUtils - -using LinearAlgebra -using TestItemRunner - -include("transmons.jl") -include("rydberg.jl") -include("cats.jl") - -end diff --git a/src/quantum_system_templates/cats.jl b/src/quantum_system_templates/cats.jl deleted file mode 100644 index 57c4786..0000000 --- a/src/quantum_system_templates/cats.jl +++ /dev/null @@ -1,61 +0,0 @@ -export CatSystem -export coherent_ket -export get_cat_controls - -function coherent_ket(α::Union{Real, Complex}, levels::Int) - return [exp(-0.5 * abs2(α)) * α^n / sqrt(factorial(n)) for n in 0:levels-1] -end - -function CatSystem(; - g2::Real=0.36, - χ_aa::Real=-7e-3, - χ_bb::Real=-32, - χ_ab::Real=0.79, - κa::Real=53e-3, - κb::Real=13, - cat_levels::Int=13, - buffer_levels::Int=3, - prefactor::Real=1, -) - params = Dict( - :g2 => prefactor * g2, - :χ_aa => prefactor * χ_aa, - :χ_bb => prefactor * χ_bb, - :χ_ab => prefactor * χ_ab, - :κa => prefactor * κa, - :κb => prefactor * κb, - :cat_levels => cat_levels, :buffer_levels => buffer_levels, :prefactor=>prefactor - ) - # Cat ⊗ Buffer - a = annihilate(cat_levels) ⊗ Matrix(1.0I, buffer_levels, buffer_levels) - b = Matrix(1.0I, cat_levels, cat_levels) ⊗ annihilate(buffer_levels) - - H_drift = -χ_aa/2 * a'a'a*a - χ_bb/2 * b'b'b*b - χ_ab * a'a*b'b + g2 * a'a'b + conj(g2) * a*a*b' - - # buffer drive, kerr-correction drive - H_drives = [b + b', a'a] - - L_dissipators = [√κa * a, √κb * b] - - H_drift *= 2π - H_drives .*= 2π - L_dissipators .*= sqrt(2π) - - return QuantumSystem( - H_drift, - H_drives, - L_dissipators; - params=params - ) -end - -function get_cat_controls(sys::AbstractQuantumSystem, α::Real, T::Int) - @assert haskey(sys.params, :g2) "Requires photon transfer coupling between buffer and cat" - @assert haskey(sys.params, :χ_aa) "Requires Kerr coupling for cat" - buffer_drive = abs2(α) * sys.params[:g2] - cat_kerr_correction = (2.0 * abs2(α) + 1.0) * sys.params[:χ_aa] - return stack([ - fill(buffer_drive, T), - fill(cat_kerr_correction, T) - ], dims=1) -end diff --git a/src/quantum_system_templates/rydberg.jl b/src/quantum_system_templates/rydberg.jl deleted file mode 100644 index ca9b34f..0000000 --- a/src/quantum_system_templates/rydberg.jl +++ /dev/null @@ -1,116 +0,0 @@ -export RydbergChainSystem - -function generate_pattern(N::Int, i::Int) - # Create an array filled with 'I' - qubits = fill('I', N) - # Insert 'n' at position i and i+1, ensuring it doesn't exceed the array bounds - if i <= N && i+1 <= N - qubits[i] = 'n' - qubits[i+1] = 'n' - end - return join(qubits) -end -function generate_pattern_with_gap(N::Int, i::Int, gap::Int) - # Create an array filled with 'I' - qubits = fill('I', N) - # Insert 'n' at position i and i+gap+1, ensuring it doesn't exceed the array bounds - if i <= N && i+gap+1 <= N - qubits[i] = 'n' - qubits[i+gap+1] = 'n' - end - return join(qubits) -end - -""" -Embed a character into a string at a specific position. -""" -function lift(x::Char,i::Int, N::Int) - qubits = fill('I', N) - qubits[i] = x - return join(qubits) -end -@doc raw""" - RydbergChainSystem(; - N::Int=3, # number of atoms - C::Float64=862690*2π, - distance::Float64=10.0, # μm - cutoff_order::Int=2, # 1 is nearest neighbor, 2 is next-nearest neighbor, etc. - local_detune::Bool=false, # If true, include one local detuning pattern. - all2all::Bool=true, # If true, include all-to-all interactions. - ignore_Y_drive::Bool=false, # If true, ignore the Y drive. (In the experiments, X&Y drives are implemented by Rabi amplitude and its phase.) - ) -> QuantumSystem - -Returns a `QuantumSystem` object for the Rydberg atom chain in the spin basis - |g⟩ = |0⟩ = [1, 0], |r⟩ = |1⟩ = [0, 1]. - -```math -H = \sum_i 0.5*\Omega_i(t)\cos(\phi_i(t)) \sigma_i^x - 0.5*\Omega_i(t)\sin(\phi_i(t)) \sigma_i^y - \sum_i \Delta_i(t)n_i + \sum_{i [1 0; 0 1], :X => [0 1; 1 0], :Y => [0 -im; im 0], :Z => [1 0; 0 -1], :n => [0 0; 0 1]) - - if all2all - H_drift = zeros(ComplexF64, 2^N, 2^N) - for gap in 0:N-2 - for i in 1:N-gap-1 - H_drift += C * operator_from_string( - generate_pattern_with_gap(N, i, gap), - lookup = PAULIS - ) / ((gap + 1) * distance)^6 - end - end - else - if cutoff_order == 1 - H_drift = sum([C*operator_from_string(generate_pattern(N,i),lookup=PAULIS)/(distance^6) for i in 1:N-1]) - elseif cutoff_order == 2 - H_drift = sum([C*operator_from_string(generate_pattern(N,i),lookup=PAULIS)/(distance^6) for i in 1:N-1]) - H_drift += sum([C*operator_from_string(generate_pattern_with_gap(N,i,1),lookup=PAULIS)/((2*distance)^6) for i in 1:N-2]) - else - error("Higher cutoff order not supported") - end - end - - H_drives = Matrix{ComplexF64}[] - - # Add global X drive - Hx = sum([0.5*operator_from_string(lift('X',i,N), lookup=PAULIS) for i in 1:N]) - push!(H_drives, Hx) - - if !ignore_Y_drive - # Add global Y drive - Hy = sum([0.5*operator_from_string(lift('Y',i,N), lookup=PAULIS) for i in 1:N]) - push!(H_drives, Hy) - end - - # Add global detuning - H_detune = -sum([operator_from_string(lift('n',i,N), lookup=PAULIS) for i in 1:N]) - push!(H_drives, H_detune) - - return QuantumSystem( - H_drift, - H_drives - ) -end - -@testitem "Rydberg system test" begin - @test RydbergChainSystem(N=3,cutoff_order=2,all2all=false) isa QuantumSystem -end diff --git a/src/quantum_system_templates/transmons.jl b/src/quantum_system_templates/transmons.jl deleted file mode 100644 index 2338412..0000000 --- a/src/quantum_system_templates/transmons.jl +++ /dev/null @@ -1,242 +0,0 @@ -export TransmonSystem -export TransmonDipoleCoupling -export MultiTransmonSystem - -@doc raw""" - TransmonSystem(; - ω::Float64=4.4153, # GHz - δ::Float64=0.17215, # GHz - levels::Int=3, - lab_frame::Bool=false, - frame_ω::Float64=ω, - ) -> QuantumSystem - -Returns a `QuantumSystem` object for a transmon qubit, with the Hamiltonian - -```math -H = \omega a^\dagger a - \frac{\delta}{2} a^\dagger a^\dagger a a -``` - -where `a` is the annihilation operator. - -# Keyword Arguments -- `ω`: The frequency of the transmon, in GHz. -- `δ`: The anharmonicity of the transmon, in GHz. -- `levels`: The number of levels in the transmon. -- `lab_frame`: Whether to use the lab frame Hamiltonian, or an ω-rotating frame. -- `frame_ω`: The frequency of the rotating frame, in GHz. -- `mutiply_by_2π`: Whether to multiply the Hamiltonian by 2π, set to true by default because the frequency is in GHz. -- `lab_frame_type`: The type of lab frame Hamiltonian to use, one of (:duffing, :quartic, :cosine). -- `drives`: Whether to include drives in the Hamiltonian. -""" -function TransmonSystem(; - ω::Float64=4.0, # GHz - δ::Float64=0.2, # GHz - levels::Int=3, - lab_frame::Bool=false, - frame_ω::Float64=lab_frame ? 0.0 : ω, - mutiply_by_2π::Bool=true, - lab_frame_type::Symbol=:duffing, - drives::Bool=true, -) - - @assert lab_frame_type ∈ (:duffing, :quartic, :cosine) "lab_frame_type must be one of (:duffing, :quartic, :cosine)" - - if lab_frame - if frame_ω ≉ 0.0 - frame_ω = 0.0 - end - end - - if frame_ω ≉ 0.0 - lab_frame = false - end - - a = annihilate(levels) - - if lab_frame - if lab_frame_type == :duffing - H_drift = ω * a' * a - δ / 2 * a' * a' * a * a - elseif lab_frame_type == :quartic - ω₀ = ω + δ - H_drift = ω₀ * a' * a - δ / 12 * (a + a')^4 - elseif lab_frame_type == :cosine - ω₀ = ω + δ - E_C = δ - E_J = ω₀^2 / 8E_C - n̂ = im / 2 * (E_J / 2E_C)^(1/4) * (a - a') - φ̂ = (2E_C / E_J)^(1/4) * (a + a') - H_drift = 4 * E_C * n̂^2 - E_J * cos(φ̂) - # H_drift = 4 * E_C * n̂^2 - E_J * (I - φ̂^2 / 2 + φ̂^4 / 24) - end - else - H_drift = (ω - frame_ω) * a' * a - δ / 2 * a' * a' * a * a - end - - if drives - H_drives = [a + a', 1.0im * (a - a')] - else - H_drives = Matrix{ComplexF64}[] - end - - if mutiply_by_2π - H_drift *= 2π - H_drives .*= 2π - end - - params = Dict{Symbol, Any}( - :ω => ω, - :δ => δ, - :levels => levels, - :lab_frame => lab_frame, - :frame_ω => frame_ω, - :mutiply_by_2π => mutiply_by_2π, - :lab_frame_type => lab_frame_type, - :drives => drives, - ) - - return QuantumSystem( - H_drift, - H_drives; - params=params - ) -end - -@doc raw""" - TransmonDipoleCoupling( - g_ij::Float64, - pair::Tuple{Int, Int}, - subsystem_levels::Vector{Int}; - lab_frame::Bool=false, - ) -> QuantumSystemCoupling - - TransmonDipoleCoupling( - g_ij::Float64, - pair::Tuple{Int, Int}, - sub_systems::Vector{QuantumSystem}; - kwargs... - ) -> QuantumSystemCoupling - -Returns a `QuantumSystemCoupling` object for a transmon qubit. In the lab frame, the Hamiltonian coupling term is - -```math -H = g_{ij} (a_i + a_i^\dagger) (a_j + a_j^\dagger) -``` - -In the rotating frame, the Hamiltonian coupling term is - -```math -H = g_{ij} (a_i a_j^\dagger + a_i^\dagger a_j) -``` - -where `a_i` is the annihilation operator for the `i`th transmon. - -""" -function TransmonDipoleCoupling end - -function TransmonDipoleCoupling( - g_ij::Float64, - pair::Tuple{Int, Int}, - subsystem_levels::Vector{Int}; - lab_frame::Bool=false, - mulitply_by_2π::Bool=true, -) - i, j = pair - a_i = lift(annihilate(subsystem_levels[i]), i, subsystem_levels) - a_j = lift(annihilate(subsystem_levels[j]), j, subsystem_levels) - - if lab_frame - op = g_ij * (a_i + a_i') * (a_j + a_j') - else - op = g_ij * (a_i * a_j' + a_i' * a_j) - end - - if mulitply_by_2π - op *= 2π - end - - params = Dict{Symbol, Any}( - :lab_frame => lab_frame, - :mulitply_by_2π => mulitply_by_2π, - ) - - return QuantumSystemCoupling( - op, - g_ij, - pair, - subsystem_levels, - TransmonDipoleCoupling, - params - ) -end - -function TransmonDipoleCoupling( - g_ij::Float64, - pair::Tuple{Int, Int}, - sub_systems::Vector{QuantumSystem}; - kwargs... -) - subsystem_levels = [sys.levels for sys ∈ sub_systems] - return TransmonDipoleCoupling(g_ij, pair, subsystem_levels; kwargs...) -end - -""" - MultiTransmonSystem( - ωs::AbstractVector{Float64}, - δs::AbstractVector{Float64}, - gs::AbstractMatrix{Float64}; - levels_per_transmon::Int = 3, - subsystem_levels::AbstractVector{Int} = fill(levels_per_transmon, length(ωs)), - lab_frame=false, - subsystems::AbstractVector{Int} = 1:length(ωs), - subsystem_drive_indices::AbstractVector{Int} = 1:length(ωs), - kwargs... - ) -> CompositeQuantumSystem - -Returns a `CompositeQuantumSystem` object for a multi-transmon system. -""" -function MultiTransmonSystem( - ωs::AbstractVector{Float64}, - δs::AbstractVector{Float64}, - gs::AbstractMatrix{Float64}; - levels_per_transmon::Int = 3, - subsystem_levels::AbstractVector{Int} = fill(levels_per_transmon, length(ωs)), - lab_frame=false, - subsystems::AbstractVector{Int} = 1:length(ωs), - subsystem_drive_indices::AbstractVector{Int} = 1:length(ωs), - kwargs... -) - n_subsystems = length(ωs) - @assert length(δs) == n_subsystems - @assert size(gs) == (n_subsystems, n_subsystems) - - systems = QuantumSystem[] - - for (i, (ω, δ, levels)) ∈ enumerate(zip(ωs, δs, subsystem_levels)) - if i ∈ subsystems - sysᵢ = TransmonSystem( - levels=levels, - ω=ω, - δ=δ, - lab_frame=lab_frame, - drives=i ∈ subsystem_drive_indices - ) - push!(systems, sysᵢ) - end - end - - couplings = QuantumSystemCoupling[] - - for i = 1:n_subsystems-1 - for j = i+1:n_subsystems - if i ∈ subsystems && j ∈ subsystems - push!( - couplings, - TransmonDipoleCoupling(gs[i, j], (i, j), systems; lab_frame=lab_frame) - ) - end - end - end - - return CompositeQuantumSystem(systems, couplings) -end