From 6ea353db9942963e611beab15d97376679194855 Mon Sep 17 00:00:00 2001 From: hanakl Date: Fri, 16 May 2025 00:31:41 -0700 Subject: [PATCH 1/3] Add decoherence and subset GHZ projection --- examples/GHZsetup/fixed_time.jl | 98 +++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 examples/GHZsetup/fixed_time.jl diff --git a/examples/GHZsetup/fixed_time.jl b/examples/GHZsetup/fixed_time.jl new file mode 100644 index 00000000..2eea91dc --- /dev/null +++ b/examples/GHZsetup/fixed_time.jl @@ -0,0 +1,98 @@ +using ResumableFunctions +using ConcurrentSim +using Revise +using QuantumSavory +using QuantumSavory.ProtocolZoo +using QuantumClifford: ghz +const bell = StabilizerState("XX ZZ") +const perfect_pair = (Z1⊗Z1 + Z2⊗Z2) / sqrt(2) +const perfect_pair_dm = SProjector(perfect_pair) +const mixed_dm = MixedState(perfect_pair_dm) + +noisy_pair_func_depol(p) = p*perfect_pair_dm + (1-p)*mixed_dm + +function noisy_pair_func(F) + p = (4*F-1)/3 + return noisy_pair_func_depol(p) +end + +S = 5 # number of sensors +F = 0.99 # fidelity + +noisy_pair = noisy_pair_func(F) + +@resumable function GHZ_projection(sim, net, S; time=0.1) + hub_idx = S + 1 + while true + queries = [] + incomplete = false + # check & wait for all entanglements + for i in 1:S + q = query(net[hub_idx], EntanglementCounterpart, i, ❓; locked=false, assigned=true) + if isnothing(q) + @yield timeout(sim, 0.1) + incomplete = true + break + end + push!(queries, q) + end + if incomplete + continue + end + + @debug "All entanglements are ready, at $(now(sim))" + + # GHZ -> computational basis + + # This "collects" parity information into qubit 1 + for i in 2:S + apply!([net[hub_idx, 1], net[hub_idx, i]], CNOT) + end + apply!(net[hub_idx, 1], H) + + # measure & send correction message + m1 = project_traceout!(net[hub_idx, 1], Z) + + # If the result is '1' (m1 == 2), the global GHZ state is flipped (X gate needed) + if m1 == 2 + msg1 = Tag(EntanglementUpdateX, hub_idx, 1, 1, -1, -1, m1) + put!(channel(net, hub_idx => 1; permit_forward=true), msg1) + end + + # If m == 2 ('1'), this indicates a relative phase flip (Z gate needed) + for i in 2:S + m = project_traceout!(net[hub_idx, i], Z) + msg = Tag(EntanglementUpdateZ, hub_idx, i, 1, -1, -1, m) + put!(channel(net, hub_idx => i; permit_forward=true), msg) + end + + @yield timeout(sim, time) + end +end + + +# run the simulation + +net = RegisterNet([[Register(1, T2Dephasing(1.0)) for _ in 1:S]; Register(S, T2Dephasing(1.0))]) + +sim = get_time_tracker(net) + +for i in 1:S + # for entanglements and incoming correction messages + tracker = EntanglementTracker(sim, net, i) + @process tracker() +end + +for i in 1:S + # entangle sensors with the hub (S+1) + eprot = EntanglerProt(sim, net, i, S + 1; pairstate=noisy_pair, chooseA=1, chooseB=i, rounds=1, success_prob=1.) + @process eprot() +end + +@process GHZ_projection(sim, net, S) +run(sim, 10) + +ghz_state = StabilizerState(ghz(S)) + +# a bit noisy, but should be close to 1 +observable([net[i,1] for i in 1:S], projector(ghz_state)) \ No newline at end of file From 24a872100dd456283d8c5a2f5c1b950935e04498 Mon Sep 17 00:00:00 2001 From: hanakl Date: Tue, 20 May 2025 22:31:05 -0700 Subject: [PATCH 2/3] update methods --- examples/GHZsetup/fixed_time.jl | 115 +++++++++++++++++++------------- 1 file changed, 70 insertions(+), 45 deletions(-) diff --git a/examples/GHZsetup/fixed_time.jl b/examples/GHZsetup/fixed_time.jl index 2eea91dc..9b9e75ce 100644 --- a/examples/GHZsetup/fixed_time.jl +++ b/examples/GHZsetup/fixed_time.jl @@ -4,6 +4,10 @@ using Revise using QuantumSavory using QuantumSavory.ProtocolZoo using QuantumClifford: ghz + +using Logging +global_logger(ConsoleLogger(stderr, Logging.Debug)) + const bell = StabilizerState("XX ZZ") const perfect_pair = (Z1⊗Z1 + Z2⊗Z2) / sqrt(2) const perfect_pair_dm = SProjector(perfect_pair) @@ -18,81 +22,102 @@ end S = 5 # number of sensors F = 0.99 # fidelity +entanglemnt_success_prob = 0.05 +fixed_time = 1 # time for EntanglerProts noisy_pair = noisy_pair_func(F) -@resumable function GHZ_projection(sim, net, S; time=0.1) +mutable struct EntangledNodes + nodes::Vector{Int} +end + +@resumable function GHZ_projection(sim, net, S, fixed_time, entangled; time=0.1) hub_idx = S + 1 while true - queries = [] - incomplete = false - # check & wait for all entanglements + @yield timeout(sim, fixed_time + 0.1) # TODO: Fix this for multiple rounds (probably tag-based) + entangled_ = Int[] for i in 1:S q = query(net[hub_idx], EntanglementCounterpart, i, ❓; locked=false, assigned=true) - if isnothing(q) - @yield timeout(sim, 0.1) - incomplete = true - break + if !isnothing(q) + push!(entangled_, q.tag.data[2]) end - push!(queries, q) end - if incomplete - continue - end - - @debug "All entanglements are ready, at $(now(sim))" - - # GHZ -> computational basis + entangled.nodes = entangled_ + if length(entangled.nodes) == 0 # no entanglements + @debug "All entanglement failed" + break + else + #@debug "$(length(entangled)) entanglements are ready, at $(now(sim))" + println("$(length(entangled.nodes)) entanglements are ready, at $(now(sim))") + + # GHZ -> computational basis + + first = entangled.nodes[1] + others = filter(i -> i != first, entangled.nodes) + + # This "collects" parity information into the first entangled qubit + for i in others + apply!([net[hub_idx, first], net[hub_idx, i]], CNOT) + end + apply!(net[hub_idx, first], H) - # This "collects" parity information into qubit 1 - for i in 2:S - apply!([net[hub_idx, 1], net[hub_idx, i]], CNOT) - end - apply!(net[hub_idx, 1], H) + # measure & send correction message + m1 = project_traceout!(net[hub_idx, first], Z) - # measure & send correction message - m1 = project_traceout!(net[hub_idx, 1], Z) + # If the result is '1' (m1 == 2), the global GHZ state is flipped (X gate needed) + if m1 == 2 + msg1 = Tag(EntanglementUpdateX, hub_idx, first, 1, -1, -1, m1) + put!(channel(net, hub_idx => first; permit_forward=true), msg1) + end - # If the result is '1' (m1 == 2), the global GHZ state is flipped (X gate needed) - if m1 == 2 - msg1 = Tag(EntanglementUpdateX, hub_idx, 1, 1, -1, -1, m1) - put!(channel(net, hub_idx => 1; permit_forward=true), msg1) - end + # If m == 2 ('1'), this indicates a relative phase flip (Z gate needed) + for i in others + m = project_traceout!(net[hub_idx, i], Z) + msg = Tag(EntanglementUpdateZ, hub_idx, i, 1, -1, -1, m) + put!(channel(net, hub_idx => i; permit_forward=true), msg) + end - # If m == 2 ('1'), this indicates a relative phase flip (Z gate needed) - for i in 2:S - m = project_traceout!(net[hub_idx, i], Z) - msg = Tag(EntanglementUpdateZ, hub_idx, i, 1, -1, -1, m) - put!(channel(net, hub_idx => i; permit_forward=true), msg) + @yield timeout(sim, time) end - - @yield timeout(sim, time) end end +@resumable function entangler(sim, net, S, fixed_time) + procs = [] + for i in 1:S + # entangle sensors with the hub (S+1) + eprot = EntanglerProt(sim, net, i, S + 1; pairstate=noisy_pair, chooseA=1, chooseB=i, success_prob=entanglemnt_success_prob) + @process eprot() + end + @yield timeout(sim, fixed_time) + for p in procs + cancel!(p) + end +end # run the simulation -net = RegisterNet([[Register(1, T2Dephasing(1.0)) for _ in 1:S]; Register(S, T2Dephasing(1.0))]) +net = RegisterNet([[Register(1, Depolarization(1.0)) for _ in 1:S]; Register(S, Depolarization(1.0))]) sim = get_time_tracker(net) +entangled_nodes = EntangledNodes(Int[]) + for i in 1:S # for entanglements and incoming correction messages tracker = EntanglementTracker(sim, net, i) @process tracker() end -for i in 1:S - # entangle sensors with the hub (S+1) - eprot = EntanglerProt(sim, net, i, S + 1; pairstate=noisy_pair, chooseA=1, chooseB=i, rounds=1, success_prob=1.) - @process eprot() -end +@process entangler(sim, net, S, fixed_time) -@process GHZ_projection(sim, net, S) -run(sim, 10) +@process GHZ_projection(sim, net, S, fixed_time, entangled_nodes) +run(sim, 3) -ghz_state = StabilizerState(ghz(S)) +ghz_state = StabilizerState(ghz(length(entangled[]))) # a bit noisy, but should be close to 1 -observable([net[i,1] for i in 1:S], projector(ghz_state)) \ No newline at end of file +observable([net[i,1] for i in entangled], projector(ghz_state)) + +entangled_nodes.nodes +isnothing([]) \ No newline at end of file From 57e1e3147bdf3f836c97e334e5ff927e02dcf015 Mon Sep 17 00:00:00 2001 From: hanakl Date: Tue, 20 May 2025 22:46:08 -0700 Subject: [PATCH 3/3] fix conversion issue --- examples/GHZsetup/fixed_time.jl | 44 +++++++++++++++------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/examples/GHZsetup/fixed_time.jl b/examples/GHZsetup/fixed_time.jl index 9b9e75ce..f576d61e 100644 --- a/examples/GHZsetup/fixed_time.jl +++ b/examples/GHZsetup/fixed_time.jl @@ -22,8 +22,8 @@ end S = 5 # number of sensors F = 0.99 # fidelity -entanglemnt_success_prob = 0.05 -fixed_time = 1 # time for EntanglerProts +entanglemnt_success_prob = 0.001 +fixed_time = 0.5 # time for EntanglerProts noisy_pair = noisy_pair_func(F) @@ -31,9 +31,10 @@ mutable struct EntangledNodes nodes::Vector{Int} end -@resumable function GHZ_projection(sim, net, S, fixed_time, entangled; time=0.1) +@resumable function GHZ_projection(sim, net, S, fixed_time, entangled; rounds=1, time=0.1) hub_idx = S + 1 - while true + while rounds != 0 + println(entangled.nodes) @yield timeout(sim, fixed_time + 0.1) # TODO: Fix this for multiple rounds (probably tag-based) entangled_ = Int[] for i in 1:S @@ -43,35 +44,32 @@ end end end entangled.nodes = entangled_ + println(entangled.nodes) if length(entangled.nodes) == 0 # no entanglements @debug "All entanglement failed" break else - #@debug "$(length(entangled)) entanglements are ready, at $(now(sim))" - println("$(length(entangled.nodes)) entanglements are ready, at $(now(sim))") + @debug "$(length(entangled)) entanglements are ready, at $(now(sim))" # GHZ -> computational basis - - first = entangled.nodes[1] - others = filter(i -> i != first, entangled.nodes) # This "collects" parity information into the first entangled qubit - for i in others - apply!([net[hub_idx, first], net[hub_idx, i]], CNOT) + for i in entangled.nodes[2:end] + apply!([net[hub_idx, entangled.nodes[1]], net[hub_idx, i]], CNOT) end - apply!(net[hub_idx, first], H) + apply!(net[hub_idx, entangled.nodes[1]], H) # measure & send correction message - m1 = project_traceout!(net[hub_idx, first], Z) + m1 = project_traceout!(net[hub_idx, entangled.nodes[1]], Z) # If the result is '1' (m1 == 2), the global GHZ state is flipped (X gate needed) if m1 == 2 - msg1 = Tag(EntanglementUpdateX, hub_idx, first, 1, -1, -1, m1) - put!(channel(net, hub_idx => first; permit_forward=true), msg1) + msg1 = Tag(EntanglementUpdateX, hub_idx, entangled.nodes[1], 1, -1, -1, m1) + put!(channel(net, hub_idx => entangled.nodes[1]; permit_forward=true), msg1) end # If m == 2 ('1'), this indicates a relative phase flip (Z gate needed) - for i in others + for i in entangled.nodes[2:end] m = project_traceout!(net[hub_idx, i], Z) msg = Tag(EntanglementUpdateZ, hub_idx, i, 1, -1, -1, m) put!(channel(net, hub_idx => i; permit_forward=true), msg) @@ -79,10 +77,11 @@ end @yield timeout(sim, time) end + rounds==-1 || (rounds -= 1) end end -@resumable function entangler(sim, net, S, fixed_time) +@resumable function entangler(sim, net, S, fixed_time, entanglemnt_success_prob) procs = [] for i in 1:S # entangle sensors with the hub (S+1) @@ -109,15 +108,12 @@ for i in 1:S @process tracker() end -@process entangler(sim, net, S, fixed_time) +@process entangler(sim, net, S, fixed_time,entanglemnt_success_prob) @process GHZ_projection(sim, net, S, fixed_time, entangled_nodes) -run(sim, 3) +run(sim, 1) -ghz_state = StabilizerState(ghz(length(entangled[]))) +ghz_state = StabilizerState(ghz(length(entangled_nodes.nodes))) # a bit noisy, but should be close to 1 -observable([net[i,1] for i in entangled], projector(ghz_state)) - -entangled_nodes.nodes -isnothing([]) \ No newline at end of file +observable([net[i,1] for i in entangled_nodes.nodes], projector(ghz_state)) \ No newline at end of file