diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c517158..074d2052 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## v0.4.2 - dev +- Add a `NetworkSimulation` for accessing local entanglement id counter - Bump QuantumSymbolics and QuantumOpticsBase compat bound and bump julia compat to 1.10. ## v0.4.1 - 2024-06-05 diff --git a/Project.toml b/Project.toml index 2088201b..51a85f67 100644 --- a/Project.toml +++ b/Project.toml @@ -7,6 +7,7 @@ version = "0.4.2-dev" Cbc = "9961bab8-2fa3-5c5a-9d89-47fab24efd76" Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" ConcurrentSim = "6ed1e86c-fcaf-46a9-97e0-2b26a2cdb499" +DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" @@ -38,6 +39,7 @@ QuantumSavoryMakie = "Makie" Cbc = "1.2" Combinatorics = "1" ConcurrentSim = "1.4.1" +DataStructures = "0.18.15" Distributions = "0.25.90" DocStringExtensions = "0.9" Graphs = "1.9" diff --git a/src/ProtocolZoo/ProtocolZoo.jl b/src/ProtocolZoo/ProtocolZoo.jl index 8f2f37ab..be367003 100644 --- a/src/ProtocolZoo/ProtocolZoo.jl +++ b/src/ProtocolZoo/ProtocolZoo.jl @@ -8,7 +8,7 @@ using QuantumSavory.CircuitZoo: EntanglementSwap, LocalEntanglementSwap using DocStringExtensions using Distributions: Geometric -using ConcurrentSim: Simulation, @yield, timeout, @process, now +using ConcurrentSim: Environment, @yield, timeout, @process, now import ConcurrentSim: Process import ResumableFunctions using ResumableFunctions: @resumable @@ -26,7 +26,7 @@ abstract type AbstractProtocol end get_time_tracker(prot::AbstractProtocol) = prot.sim -Process(prot::AbstractProtocol, args...; kwargs...) = Process((e,a...;k...)->prot(a...;k...), get_time_tracker(prot), args...; kwargs...) +Process(prot::AbstractProtocol, args...; kwargs...) = Process((e,a...;k...)->prot(a...;k...), get_time_tracker(prot).sim, args...; kwargs...) """ $TYPEDEF @@ -132,7 +132,7 @@ $TYPEDFIELDS """ @kwdef struct EntanglerProt{LT} <: AbstractProtocol where {LT<:Union{Float64,Nothing}} """time-and-schedule-tracking instance from `ConcurrentSim`""" - sim::Simulation # TODO check that + sim::Environment # TODO check that """a network graph of registers""" net::RegisterNet """the vertex index of node A""" @@ -164,7 +164,7 @@ $TYPEDFIELDS end """Convenience constructor for specifying `rate` of generation instead of success probability and time""" -function EntanglerProt(sim::Simulation, net::RegisterNet, nodeA::Int, nodeB::Int; rate::Union{Nothing,Float64}=nothing, kwargs...) +function EntanglerProt(sim::Environment, net::RegisterNet, nodeA::Int, nodeB::Int; rate::Union{Nothing,Float64}=nothing, kwargs...) if isnothing(rate) return EntanglerProt(;sim, net, nodeA, nodeB, kwargs...) else @@ -233,7 +233,7 @@ $TYPEDFIELDS """ @kwdef struct SwapperProt{NL,NH,CL,CH,LT} <: AbstractProtocol where {NL<:Union{Int,<:Function,Wildcard}, NH<:Union{Int,<:Function,Wildcard}, CL<:Function, CH<:Function, LT<:Union{Float64,Nothing}} """time-and-schedule-tracking instance from `ConcurrentSim`""" - sim::Simulation + sim::Environment """a network graph of registers""" net::RegisterNet """the vertex of the node where swapping is happening""" @@ -255,7 +255,7 @@ $TYPEDFIELDS end #TODO "convenience constructor for the missing things and finish this docstring" -function SwapperProt(sim::Simulation, net::RegisterNet, node::Int; kwargs...) +function SwapperProt(sim::Environment, net::RegisterNet, node::Int; kwargs...) return SwapperProt(;sim, net, node, kwargs...) end @@ -326,7 +326,7 @@ $TYPEDFIELDS """ @kwdef struct EntanglementTracker <: AbstractProtocol """time-and-schedule-tracking instance from `ConcurrentSim`""" - sim::Simulation + sim::Environment """a network graph of registers""" net::RegisterNet """the vertex of the node where the tracker is working""" @@ -405,7 +405,7 @@ $FIELDS """ @kwdef struct EntanglementConsumer{LT} <: AbstractProtocol where {LT<:Union{Float64,Nothing}} """time-and-schedule-tracking instance from `ConcurrentSim`""" - sim::Simulation + sim::Environment """a network graph of registers""" net::RegisterNet """the vertex index of node A""" @@ -418,7 +418,7 @@ $FIELDS log::Vector{Tuple{Float64, Float64, Float64}} = Tuple{Float64, Float64, Float64}[] end -function EntanglementConsumer(sim::Simulation, net::RegisterNet, nodeA::Int, nodeB::Int; kwargs...) +function EntanglementConsumer(sim::Environment, net::RegisterNet, nodeA::Int, nodeB::Int; kwargs...) return EntanglementConsumer(;sim, net, nodeA, nodeB, kwargs...) end function EntanglementConsumer(net::RegisterNet, nodeA::Int, nodeB::Int; kwargs...) diff --git a/src/QuantumSavory.jl b/src/QuantumSavory.jl index f32ec294..edebdef8 100644 --- a/src/QuantumSavory.jl +++ b/src/QuantumSavory.jl @@ -1,7 +1,6 @@ module QuantumSavory -const glcnt = Ref{Int128}(0) - +glcnt = Ref{Int128}(0) function guid() glcnt[] += 1 end @@ -25,7 +24,7 @@ import SumTypes using SumTypes: @sum_type, isvariant, @cases import Combinatorics using Combinatorics: powerset - +import DataStructures import QuantumInterface: basis, tensor, ⊗, apply!, traceout!, nsubsystems, AbstractOperator, AbstractKet, AbstractSuperOperator, Basis, SpinBasis diff --git a/src/concurrentsim.jl b/src/concurrentsim.jl index c79cacb0..d9e50cb9 100644 --- a/src/concurrentsim.jl +++ b/src/concurrentsim.jl @@ -53,3 +53,57 @@ end Base.islocked(r::RegRef) = islocked(r.reg.locks[r.idx]) ConcurrentSim.request(r::RegRef) = request(r.reg.locks[r.idx]) Base.unlock(r::RegRef) = unlock(r.reg.locks[r.idx]) + +## + +struct NetworkSimulation <: ConcurrentSim.Environment + sim::Simulation + glcnt::Ref{Int128} +end + +function NetworkSimulation() + return NetworkSimulation(Simulation(), Ref{Int128}(0)) +end + +function Base.show(io::IO, env::NetworkSimulation) + if env.sim.active_proc === nothing + print(io, "$(typeof(env)) time: $(now(env.sim)) active_process: nothing") + else + print(io, "$(typeof(env)) time: $(now(env.sim)) active_process: $(env.sim.active_proc)") + end +end + +function ConcurrentSim.now(env::NetworkSimulation) + env.sim.time +end + +function ConcurrentSim.put!(con::ConcurrentSim.Container{N, T}, amount::N; priority=zero(T)) where {N<:Real, T<:Number} + put_ev = ConcurrentSim.Put(con.env.sim) + con.put_queue[put_ev] = ConcurrentSim.ContainerKey{N,T}(con.seid+=one(UInt), amount, T(priority)) + ConcurrentSim.@callback ConcurrentSim.trigger_get(put_ev, con) + ConcurrentSim.trigger_put(put_ev, con) + put_ev +end + +function ConcurrentSim.get(con::ConcurrentSim.Container{N, T}, amount::N; priority=zero(T)) where {N<:Real, T<:Number} + get_ev = ConcurrentSim.Get(con.env.sim) + con.get_queue[get_ev] = ConcurrentSim.ContainerKey(con.seid+=one(UInt), amount, T(priority)) + ConcurrentSim.@callback ConcurrentSim.trigger_put(get_ev, con) + ConcurrentSim.trigger_get(get_ev, con) + get_ev +end + +function ConcurrentSim.timeout(env::Environment, delay::Number=0; priority=0, value::Any=nothing) + ConcurrentSim.schedule(ConcurrentSim.Timeout(env.sim), delay; priority=Int(priority), value) +end + +function ConcurrentSim.step(netsim::NetworkSimulation) + isempty(netsim.sim.heap) && throw(ConcurrentSim.EmptySchedule()) + (bev, key) = DataStructures.peek(netsim.sim.heap) + DataStructures.dequeue!(netsim.sim.heap) + netsim.sim.time = key.time + bev.state = ConcurrentSim.processed + for callback in bev.callbacks + callback() + end +end \ No newline at end of file diff --git a/src/messagebuffer.jl b/src/messagebuffer.jl index 27ba2e55..2201f8b7 100644 --- a/src/messagebuffer.jl +++ b/src/messagebuffer.jl @@ -1,5 +1,5 @@ struct MessageBuffer{T} - sim::Simulation + sim::Environment net # TODO ::RegisterNet -- this can not be typed due to circular dependency, see https://github.com/JuliaLang/julia/issues/269 node::Int buffer::Vector{NamedTuple{(:src,:tag), Tuple{Union{Nothing, Int},T}}} @@ -61,7 +61,7 @@ end end function MessageBuffer(net, node::Int, qs::Vector{NamedTuple{(:src,:channel), Tuple{Int, DelayQueue{T}}}}) where {T} - sim = get_time_tracker(net) + sim = get_time_tracker(net).sim signal = IdDict{Resource,Resource}() no_wait = Ref{Int}(0) mb = MessageBuffer{T}(sim, net, node, Tuple{Int,T}[], signal, no_wait) diff --git a/src/networks.jl b/src/networks.jl index a10dc369..05615b0d 100644 --- a/src/networks.jl +++ b/src/networks.jl @@ -16,7 +16,7 @@ end function RegisterNet(graph::SimpleGraph, registers, vertex_metadata, edge_metadata, directed_edge_metadata) env = get_time_tracker(registers[1]) - all_are_at_zero = all(iszero(ConcurrentSim.now(get_time_tracker(r))) && isempty(get_time_tracker(r).heap) && isnothing(get_time_tracker(r).active_proc) for r in registers) + all_are_at_zero = all(iszero(ConcurrentSim.now(get_time_tracker(r))) && isempty(get_time_tracker(r).sim.heap) && isnothing(get_time_tracker(r).sim.active_proc) for r in registers) all_are_same = all(env === get_time_tracker(r) for r in registers) if !all_are_same if all_are_at_zero @@ -42,10 +42,10 @@ function RegisterNet(graph::SimpleGraph, registers, vertex_metadata, edge_metada end for (;src,dst) in edges(graph) - cchannels[src=>dst] = DelayQueue{Tag}(env, 0) - qchannels[src=>dst] = QuantumChannel(env, 0) - cchannels[dst=>src] = DelayQueue{Tag}(env, 0) - qchannels[dst=>src] = QuantumChannel(env, 0) + cchannels[src=>dst] = DelayQueue{Tag}(env.sim, 0) + qchannels[src=>dst] = QuantumChannel(env.sim, 0) + cchannels[dst=>src] = DelayQueue{Tag}(env.sim, 0) + qchannels[dst=>src] = QuantumChannel(env.sim, 0) end for (v,r) in zip(vertices(graph), registers) channels = [(;src=w, channel=cchannels[w=>v]) for w in neighbors(graph, v)] diff --git a/src/states_registers.jl b/src/states_registers.jl index 90121de7..489606a7 100644 --- a/src/states_registers.jl +++ b/src/states_registers.jl @@ -26,7 +26,7 @@ struct Register # TODO better type description end function Register(traits, reprs, bg, sr, si, at) - env = ConcurrentSim.Simulation() + env = NetworkSimulation() Register(traits, reprs, bg, sr, si, at, [ConcurrentSim.Resource(env) for _ in traits], Dict{Int128, Tuple{Tag, Int64, Float64}}(), [], nothing) end Register(traits,reprs,bg,sr,si) = Register(traits,reprs,bg,sr,si,zeros(length(traits)))