Skip to content

grid entanglement with multiple paths #106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Mar 15, 2024
Merged
10 changes: 8 additions & 2 deletions src/ProtocolZoo/ProtocolZoo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,13 @@ end

@resumable function (prot::EntanglerProt)()
rounds = prot.rounds
round = 1
while rounds != 0
a = findfreeslot(prot.net[prot.nodeA], randomize=prot.randomize)
b = findfreeslot(prot.net[prot.nodeB], randomize=prot.randomize)
if isnothing(a) || isnothing(b)
isnothing(prot.retry_lock_time) && error("We do not yet support waiting on register to make qubits available") # TODO
@debug "EntanglerProt between $(prot.nodeA) and $(prot.nodeB)|round $(round): Failed to find free slots. \n Got:\n \t $a \n \t $b \n retrying..."
@yield timeout(prot.sim, prot.retry_lock_time)
continue
end
Expand All @@ -185,9 +187,11 @@ end
# tag local node b with EntanglementCounterpart remote_node_idx_a remote_slot_idx_a
tag!(b, EntanglementCounterpart, prot.nodeA, a.idx)

@debug "EntanglerProt between $(prot.nodeA) and $(prot.nodeB)|round $(round): Entangled .$(a.idx) and .$(b.idx)"
unlock(a)
unlock(b)
rounds==-1 || (rounds -= 1)
round += 1
end
end

Expand Down Expand Up @@ -232,6 +236,7 @@ end

@resumable function (prot::SwapperProt)()
rounds = prot.rounds
round = 1
while rounds != 0
reg = prot.net[prot.node]
qubit_pair = findswapablequbits(prot.net, prot.node, prot.nodeL, prot.nodeH, prot.chooseL, prot.chooseH)
Expand Down Expand Up @@ -259,15 +264,16 @@ end
# tag with EntanglementUpdateX past_local_node, past_local_slot_idx past_remote_slot_idx new_remote_node, new_remote_slot, correction
msg1 = Tag(EntanglementUpdateX, prot.node, q1.idx, tag1[3], tag2[2], tag2[3], xmeas)
put!(channel(prot.net, prot.node=>tag1[2]; permit_forward=true), msg1)
@debug "SwapperProt @$(prot.node): Send message to $(tag1[2]) | message=`$msg1`"
@debug "SwapperProt @$(prot.node)|round $(round): Send message to $(tag1[2]) | message=`$msg1`"
# send from here to new entanglement counterpart:
# tag with EntanglementUpdateZ past_local_node, past_local_slot_idx past_remote_slot_idx new_remote_node, new_remote_slot, correction
msg2 = Tag(EntanglementUpdateZ, prot.node, q2.idx, tag2[3], tag1[2], tag1[3], zmeas)
put!(channel(prot.net, prot.node=>tag2[2]; permit_forward=true), msg2)
@debug "SwapperProt @$(prot.node): Send message to $(tag2[2]) | message=`$msg2`"
@debug "SwapperProt @$(prot.node)|round $(round): Send message to $(tag2[2]) | message=`$msg2`"
unlock(q1)
unlock(q2)
rounds==-1 || (rounds -= 1)
round += 1
end
end

Expand Down
24 changes: 14 additions & 10 deletions src/queries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ julia> queryall(r, :symbol, ❓, >(5))
@NamedTuple{slot::RegRef, tag::Tag}[]
```
"""
queryall(args...; kwargs...) = query(args..., Val{true}(); kwargs...)
queryall(args...; filo=true, kwargs...) = query(args..., Val{true}(), Val{filo}(); kwargs...)


"""
Expand Down Expand Up @@ -123,11 +123,12 @@ julia> query(r, Int, 4, <(7))

See also: [`queryall`](@ref), [`tag!`](@ref), [`W`](@ref), [`❓`](@ref)
"""
function query(reg::Register, tag::Tag, ::Val{allB}=Val{false}(); locked::Union{Nothing,Bool}=nothing, assigned::Union{Nothing,Bool}=nothing) where {allB}
find = allB ? findall : findfirst
function query(reg::Register, tag::Tag, ::Val{allB}=Val{false}(), ::Val{filo}=Val{true}(); locked::Union{Nothing,Bool}=nothing, assigned::Union{Nothing,Bool}=nothing) where {allB, filo}
find = allB ? findall : filo ? findlast : findfirst # findlast corresponds to filo because new tags are pushed at the end of the tags vector for a RegRef in `tag!`
i = find(i -> _nothingor(locked, islocked(reg[i])) && _nothingor(assigned, isassigned(reg[i])) && tag ∈ reg.tags[i],
1:length(reg))
if allB
i = filo ? reverse(i) : i # findall still starts looking from the first index, so we reverse here
return NamedTuple{(:slot, :tag), Tuple{RegRef, Tag}}[(slot=reg[i], tag=tag) for i in i]
else
isnothing(i) ? nothing : (;slot=reg[i], tag=tag)
Expand Down Expand Up @@ -157,10 +158,11 @@ julia> queryall(r[2], :symbol, 2, 3)
(depth = 1, tag = SymbolIntInt(:symbol, 2, 3)::Tag)
```
"""
function query(ref::RegRef, tag::Tag, ::Val{allB}=Val{false}()) where {allB} # TODO there is a lot of code duplication here
find = allB ? findall : findfirst
function query(ref::RegRef, tag::Tag, ::Val{allB}=Val{false}(), ::Val{filo}=Val{true}()) where {allB, filo} # TODO there is a lot of code duplication here
find = allB ? findall : filo ? findlast : findfirst # findlast corresponds to filo because new tags are pushed at the end of the tags vector for a RegRef in `tag!`
i = find(==(tag), ref.reg.tags[ref.idx])
if allB
i = filo ? reverse(i) : i # findall still starts looking from the first index, so we reverse here
return NamedTuple{(:depth, :tag), Tuple{Int, Tag}}[(depth=i, tag=tag) for i in i]
else
isnothing(i) ? nothing : (;depth=i, tag=tag)
Expand Down Expand Up @@ -309,11 +311,11 @@ for (tagsymbol, tagvariant) in pairs(tag_types)
argssig_wild = [:($a::$t) for (a,t) in zip(args, sig_wild)]
wild_checks = [:(isa($(args[i]),Wildcard) || $(args[i])(tag[$i])) for i in idx]
nonwild_checks = [:(tag[$i]==$(args[i])) for i in complement_idx]
newmethod_reg = quote function query(reg::Register, $(argssig_wild...), ::Val{allB}=Val{false}(); locked::Union{Nothing,Bool}=nothing, assigned::Union{Nothing,Bool}=nothing) where {allB}
newmethod_reg = quote function query(reg::Register, $(argssig_wild...), ::Val{allB}=Val{false}(), ::Val{filo}=Val{true}(); locked::Union{Nothing,Bool}=nothing, assigned::Union{Nothing,Bool}=nothing) where {allB, filo}
res = NamedTuple{(:slot, :tag), Tuple{RegRef, Tag}}[]
for (reg_idx, tags) in enumerate(reg.tags)
slot = reg[reg_idx]
for tag in tags
for tag in (filo ? reverse(tags) : tags)
if isvariant(tag, ($(tagsymbol,))[1]) # a weird workaround for interpolating a symbol as a symbol
(_nothingor(locked, islocked(slot)) && _nothingor(assigned, isassigned(slot))) || continue
if _all($(nonwild_checks...)) && _all($(wild_checks...))
Expand All @@ -322,7 +324,7 @@ for (tagsymbol, tagvariant) in pairs(tag_types)
end
end
end
allB ? res : nothing
allB ? res : nothing # do we need to reverse here?
end end
newmethod_mb = quote function query(mb::MessageBuffer, $(argssig_wild...))
for (depth, (src, tag)) in pairs(mb.buffer)
Expand All @@ -333,9 +335,11 @@ for (tagsymbol, tagvariant) in pairs(tag_types)
end
end
end end
newmethod_rr = quote function query(ref::RegRef, $(argssig_wild...), ::Val{allB}=Val{false}()) where {allB}
newmethod_rr = quote function query(ref::RegRef, $(argssig_wild...), ::Val{allB}=Val{false}(), ::Val{filo}=Val{true}()) where {allB, filo}
res = NamedTuple{(:depth, :tag), Tuple{Int, Tag}}[]
for (depth, tag) in pairs(ref.reg.tags[ref.idx])
tags = filo ? reverse(ref.reg.tags[ref.idx]) : ref.reg.tags[ref.idx]
for (depth, tag) in pairs(tags) # no `reverse` dispatch on `Base.Pairs`, so we end up with the original depth but only the order of tags reversed
depth = filo ? length(ref.reg.tags[ref.idx]) + 1 - depth : depth # to adjust the depth
if isvariant(tag, ($(tagsymbol,))[1]) # a weird workaround for interpolating a symbol as a symbol
if _all($(nonwild_checks...)) && _all($(wild_checks...))
allB ? push!(res, (;depth, tag)) : return (;depth, tag)
Expand Down
Loading