Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
change to variational name, add iso for var_G, update rollouts
  • Loading branch information
andgoldschmidt committed Apr 1, 2025
commit 5710bfb17f9f76407417eda8f7dc122eddfd946b
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "PiccoloQuantumObjects"
uuid = "5a402ddf-f93c-42eb-975e-5582dcda653d"
authors = ["Aaron Trowbridge <[email protected]> and contributors"]
version = "0.3.1"
version = "0.3.2"

[deps]
ExponentialAction = "e24c0720-ea99-47e8-929e-571b494574d3"
Expand Down
50 changes: 50 additions & 0 deletions src/isomorphisms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,32 @@ function iso_D(L::AbstractMatrix{ℂ}) where ℂ <: Number
return iso(kron(conj(L), L) - 1 / 2 * ad_vec(L'L, anti=true))
end

@doc raw"""
var_G(G::AbstractMatrix{<:Real}, G_vars::AbstractVector{<:AbstractMatrix{<:Real}})

Returns the variational generator of `G` with variational derivatives, `G_vars`.

The variational generator is
```math
\text{var}_G(G, [G_a, G_b]) = \mqty( G & 0 & 0 \\ G_a & G & 0 \\ G_b & 0 & G )
```
where `G` is the isomorphism of a Hamiltonian and `G_a` and `G_b` are the variational
derivatives of `G` for parameters `a` and `b`, respectively.
"""
function var_G(
G::AbstractMatrix{ℝ},
G_vars::AbstractVector{<:AbstractMatrix{<:Real}}
) where ℝ <: Real
n, m = size(G)
v = length(G_vars)
G_0 = kron(I(v + 1), G)
G_V = spzeros(ℝ, (v + 1) * n, (v + 1) * m)
for i = eachindex(G_vars)
G_V[i * n + 1:(i + 1) * n, 1:m] .= G_vars[i]
end
return G_0 + G_V
end

# *************************************************************************** #

@testitem "Test ket isomorphisms" begin
Expand Down Expand Up @@ -304,4 +330,28 @@ end
@test ad_H ≈ [0 -im -im 0; im 0 0 -im; im 0 0 -im; 0 im im 0]
end

@testitem "Test variational G isomorphism" begin
using PiccoloQuantumObjects: Isomorphisms.var_G

G = [1.0 2.0; 3.0 4.0]
G_var1 = [0.0 1.0; 1.0 0.0]
G_var2 = [0.0 0.0; 1.0 1.0]

G_vars = [G_var1]
Ĝ = var_G(G, G_vars)
@test Ĝ ≈ [1.0 2.0 0.0 0.0;
3.0 4.0 0.0 0.0;
0.0 1.0 1.0 2.0;
1.0 0.0 3.0 4.0]

G_vars = [G_var1, G_var2]
Ĝ = var_G(G, G_vars)
@test Ĝ ≈ [1.0 2.0 0.0 0.0 0.0 0.0;
3.0 4.0 0.0 0.0 0.0 0.0;
0.0 1.0 1.0 2.0 0.0 0.0;
1.0 0.0 3.0 4.0 0.0 0.0;
0.0 0.0 0.0 0.0 1.0 2.0;
1.0 1.0 0.0 0.0 3.0 4.0]
end

end
245 changes: 75 additions & 170 deletions src/quantum_systems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module QuantumSystems
export AbstractQuantumSystem
export QuantumSystem
export OpenQuantumSystem
export ParameterizedQuantumSystem
export VariationalQuantumSystem

export get_drift
export get_drives
Expand Down Expand Up @@ -295,193 +295,98 @@ struct OpenQuantumSystem <: AbstractQuantumSystem

end

# ****************************************************************************** #
# ----------------------------------------------------------------------------- #
# VariationalQuantumSystem
# ----------------------------------------------------------------------------- #

struct ParameterizedQuantumSystem <: AbstractQuantumSystem
# TODO: Open quantum systems?

struct VariationalQuantumSystem <: AbstractQuantumSystem
H::Function
G::Function
Gₐ::Vector{Function}
∂G::Function
∂G::Function
G_vars::Vector{Function}
∂G_vars::Vector{Function}
n_drives::Int
levels::Int
params::Dict{Symbol, Any}

function ParameterizedQuantumSystem end
function VariationalQuantumSystem end

function VariationalQuantumSystem(
H_drift::AbstractMatrix{<:Number},
H_drives::AbstractVector{<:AbstractMatrix{<:Number}},
H_vars::AbstractVector{<:AbstractMatrix{<:Number}};
params::Dict{Symbol, <:Any}=Dict{Symbol, Any}()
)
@assert !isempty(H_vars) "At least one variational operator is required"

levels = size(H_drift, 1)
H_drift = sparse(H_drift)
G_drift = sparse(Isomorphisms.G(H_drift))

n_drives = length(H_drives)
H_drives = sparse.(H_drives)
G_drives = sparse.(Isomorphisms.G.(H_drives))

G_vars = [a -> Isomorphisms.G(sparse(H)) for H in H_vars]

if n_drives == 0
H = a -> H_drift
G = a -> G_drift
∂G = a -> 0
∂G_vars = [a -> 0 for G in G_vars]
else
H = a -> H_drift + sum(a .* H_drives)
G = a -> G_drift + sum(a .* G_drives)
∂G = a -> G_drives
∂G_vars = [a -> [spzeros(size(G)) for G in G_drives] for G in G_vars]
end

function ParameterizedQuantumSystem(base_system::QuantumSystem, sensitivity_systems::Vector{QuantumSystem})
return new(
base_system.H,
base_system.G,
[sys.G for sys ∈ sensitivity_systems],
base_system.∂G,
base_system.n_drives,
base_system.levels,
base_system.params
H,
G,
∂G,
G_vars,
∂G_vars,
n_drives,
levels,
params
)
end

function ParameterizedQuantumSystem(system::ParameterizedQuantumSystem, indices::AbstractVector{Int64})
return new(
system.H,
system.G,
system.Gₐ[indices],
system.∂G,
system.n_drives,
system.levels,
system.params
function VariationalQuantumSystem(
H_drives::AbstractVector{<:AbstractMatrix{ℂ}},
H_vars::AbstractVector{<:AbstractMatrix{<:Number}};
kwargs...
) where ℂ <: Number
@assert !isempty(H_drives) "At least one drive is required"
@assert !isempty(H_vars) "At least one variational operator is required"
return VariationalQuantumSystem(
spzeros(ℂ, size(H_drives[1])),
H_drives,
H_vars;
kwargs...
)
end

function VariationalQuantumSystem(
H::Function,
H_vars::AbstractVector{<:Function},
n_drives::Int;
params::Dict{Symbol, <:Any}=Dict{Symbol, Any}()
)
@assert !isempty(H_vars) "At least one variational operator is required"
G = a -> Isomorphisms.G(sparse(H(a)))
∂G = generator_jacobian(G)
G_vars = [a -> Isomorphisms.G(sparse(H(a))) for H in H_vars]
∂G_vars = [generator_jacobian(G) for G in G_vars]
levels = size(H(zeros(n_drives)), 1)
return new(H, G, G_vars, ∂G, ∂G_vars, n_drives, levels, params)
end
end





# struct ParameterizedQuantumSystem <: AbstractQuantumSystem
# H::Function
# G::Function
# Gₐ::Function
# ∂G::Function
# n_drives::Int
# levels::Int
# params::Dict{Symbol, Any}

# function ParameterizedQuantumSystem end

# function ParameterizedQuantumSystem(
# H_drift::AbstractMatrix{<:Number},
# H_drives::Vector{<:AbstractMatrix{<:Number}},
# Hₐ_drives::Vector{<:AbstractMatrix{<:Number}};
# params::Dict{Symbol, <:Any}=Dict{Symbol, Any}()
# )
# levels = size(H_drift, 1)
# H_drift = sparse(H_drift)
# G_drift = sparse(Isomorphisms.G(H_drift))

# n_drives = length(H_drives)
# H_drives = sparse.(H_drives)
# G_drives = sparse.(Isomorphisms.G.(H_drives))

# Gₐ_drives = sparse.(Isomorphisms.G.(Hₐ_drives))

# if n_drives == 0
# H = a -> H_drift
# G = a -> G_drift
# Gₐ = a -> 0
# ∂G = a -> 0
# else
# H = a -> H_drift + sum(a .* H_drives)
# G = a -> G_drift + sum(a .* G_drives)
# Gₐ = a -> sum(a .* Gₐ_drives)
# ∂G = a -> G_drives
# end

# return new(
# H,
# G,
# Gₐ,
# ∂G,
# n_drives,
# levels,
# params
# )
# end

# function ParameterizedQuantumSystem(
# H_drift::AbstractMatrix{<:Number},
# H_drives::Vector{<:AbstractMatrix{<:Number}},
# Hₐ_drift::AbstractMatrix{<:Number};
# params::Dict{Symbol, <:Any}=Dict{Symbol, Any}()
# )
# levels = size(H_drift, 1)
# H_drift = sparse(H_drift)
# G_drift = sparse(Isomorphisms.G(H_drift))

# n_drives = length(H_drives)
# H_drives = sparse.(H_drives)
# G_drives = sparse.(Isomorphisms.G.(H_drives))

# Gₐ_drift = sparse(Isomorphisms.G(Hₐ_drift))

# if n_drives == 0
# H = a -> H_drift
# G = a -> G_drift
# Gₐ = a -> Gₐ_drift
# ∂G = a -> 0
# else
# H = a -> H_drift + sum(a .* H_drives)
# G = a -> G_drift + sum(a .* G_drives)
# Gₐ = a -> Gₐ_drift
# ∂G = a -> G_drives
# end

# return new(
# H,
# G,
# Gₐ,
# ∂G,
# n_drives,
# levels,
# params
# )
# end

# function ParameterizedQuantumSystem(H_drives::Vector{<:AbstractMatrix{ℂ}},Hₐ_drives::Vector{<:AbstractMatrix{ℂ}}; kwargs...) where ℂ <: Number
# @assert !isempty(H_drives) "At least one drive is required"
# @assert length(Hₐ_drives) == length(H_drives) "Size has to be the same"
# return ParameterizedQuantumSystem(spzeros(ℂ, size(H_drives[1])), H_drives, Hₐ_drives; kwargs...)
# end

# function ParameterizedQuantumSystem(H_drift::AbstractMatrix{ℂ},Hₐ_drives::Vector{<:AbstractMatrix{ℂ}}; kwargs...) where ℂ <: Number
# @assert !isempty(H_drives) "At least one drive is required"
# @assert length(Hₐ_drives) == length(H_drives) "Size has to be the same"
# return ParameterizedQuantumSystem(H_drift, Matrix{ℂ}[], Hₐ_drives; kwargs...)
# end

# function ParameterizedQuantumSystem(H_drives::Vector{<:AbstractMatrix{ℂ}},Hₐ_drift::AbstractMatrix{ℂ}; kwargs...) where ℂ <: Number
# @assert !isempty(H_drives) "At least one drive is required"
# @assert length(Hₐ_drives) == length(H_drives) "Size has to be the same"
# return ParameterizedQuantumSystem(spzeros(ℂ, size(H_drives[1])), H_drives, Hₐ_drift; kwargs...)
# end

# function ParameterizedQuantumSystem(H_drift::AbstractMatrix{ℂ},Hₐ_drift::AbstractMatrix{ℂ}; kwargs...) where ℂ <: Number
# @assert !isempty(H_drives) "At least one drive is required"
# @assert length(Hₐ_drives) == length(H_drives) "Size has to be the same"
# return ParameterizedQuantumSystem(H_drift, Matrix{ℂ}[], Hₐ_drift; kwargs...)
# end

# function ParameterizedQuantumSystem(system::QuantumSystem,Hₐ_drift::AbstractMatrix{ℂ}; kwargs...) where ℂ <: Number
# return new(
# system.H,
# system.G,
# a -> sparse(Isomorphisms.G(Hₐ_drift)),
# system.∂G,
# system.n_drives,
# system.levels,
# system.params
# )

# end

# function ParameterizedQuantumSystem(system::QuantumSystem,Hₐ_drives::Vector{<:AbstractMatrix{ℂ}}; kwargs...) where ℂ <: Number

# Gₐ_drives = sparse.(Isomorphisms.G.(Hₐ_drives))
# return new(
# system.H,
# system.G,
# a -> sum(a .* Gₐ_drives),
# system.∂G,
# system.n_drives,
# system.levels,
# system.params
# )

# end

# end


#***********************************************************************************************#


Expand Down
Loading