-
Notifications
You must be signed in to change notification settings - Fork 24
Piecemaker #288
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
base: master
Are you sure you want to change the base?
Piecemaker #288
Changes from 40 commits
d8b724e
337fc92
39ae298
54d9ad2
307fd09
f7a3f47
8a14160
0957cf6
0aaeae1
be08d75
81f12d1
cef2e06
467a314
77631f2
e7d4349
5ab85ce
46681bb
badefaa
3a40643
9a12dd6
751c5b1
e9761d6
83276fe
c032be4
b81b390
87a5816
47e6134
1847ccc
c703404
38d0784
315a4ab
720fd3e
1b4b477
ff44bee
97caf9e
ca48d0d
6ae9e1a
31b6b2a
5c23612
669528c
502d33f
e82c3a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| [deps] | ||
| Bonito = "824d6782-a2ef-11e9-3a09-e5662e0c26f8" | ||
| CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" | ||
| Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" | ||
| ConcurrentSim = "6ed1e86c-fcaf-46a9-97e0-2b26a2cdb499" | ||
| DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" | ||
| Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" | ||
| GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" | ||
| GraphMakie = "1ecd5474-83a3-4783-bb4f-06765db800d2" | ||
| Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" | ||
| NetworkLayout = "46757867-2c16-5918-afeb-47bfcb05e46a" | ||
| QuantumClifford = "0525e862-1e90-11e9-3e4d-1b39d7109de1" | ||
| QuantumSavory = "2de2e421-972c-4cb5-a0c3-999c85908079" | ||
| ResumableFunctions = "c5292f4c-5179-55e1-98c5-05642aab7184" | ||
| Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" | ||
| Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" | ||
| WGLMakie = "276b4fcb-3e11-5398-bf8b-a0c2d153d008" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| # Distributing a GHZ state with a quantum entanglement switch | ||
|
|
||
| Live version is available at [areweentangledyet.com/piecemakerswitch/](https://areweentangledyet.com/piecemakerswitch/). | ||
|
|
||
| In this setup, multiple nodes (user nodes) connect to a central node (switch node) trough bipartite entangled states. The switch node performs fusion operations on these shared states to create a GHZ state among the user nodes. The goal is to do the latter as memory efficient as possible. Each of the $n$ clients can store one memory qubit in its memory buffer and one qubit at the switch side. In addition the switch's register holds a dedicated 'piecemaker' slot - a qubit in the $|+\rangle$ state, which all successfull clients fuse their switch'side qubits with. We term this protocol the _piecemaker_ protocol, see [Prielinger et al., 2025](https://arxiv.org/abs/2508.14737). | ||
|
|
||
| In each time step, $n$ entanglement generation processes run in parallel. Upon creation of an entanglement link, it is fused with the piecemaker qubit. Once all clients went through this fusion operation, the piecemaker qubit is measured. This projects the state back to the clients, resulting in the desired shared GHZ state. | ||
| The fusion operation is performed on the switch node: Let's take a client who just managed to generate a bipartide entangled state -- entangled link -- with its associated qubit at the switch side. The switch executes a `CNOT` gate on the client's qubit (target) and the piecemaker qubit (control). Next, the switch measures the client qubit in the computational basis and sends the outcome to the client (in order to apply the necessary Pauli correction). This procedure merges the bipartide state into the (entangled) state that the piecemaker qubit is currently part of, modulo any required Pauli corrections. | ||
|
|
||
| NOTE: The memories residing in the nodes' `Register`s suffer from depolarizing noise, see [`Depolarization`](https://qs.quantumsavory.org/stable/API/#QuantumSavory.Depolarization). | ||
|
|
||
| The `setup.jl` file implements all necessary base functionality. | ||
| The other files run the simulation and generate visuals in a number of different circumstances: | ||
| 1. `simple_run.jl` A single simulator script convenient for exploratory coding, running a numer of Monte Carlo simulations; | ||
| 2. `live_visualization_interactive` A web-app version of the simulator; | ||
| 3. `static_viz.jl` A script running a number of of simulations like the ones in point 1, followed by plotting the fidelity over the protocol's execution time. | ||
|
|
||
| Documentation: | ||
| - [The "How To" doc page on setting up this simulation](https://qs.quantumsavory.org/dev/howto/piecemakerswitch/piecemakerswitch) | ||
|
|
||
| ### Protocol flow | ||
|
|
||
| ```mermaid | ||
| sequenceDiagram | ||
| participant Client1 | ||
| participant ClientN | ||
| participant SwitchNode | ||
| participant Log | ||
| Note over Client1,SwitchNode: Round 1 (1 unit time) | ||
| par Entanglement Generation | ||
| Client1->>+SwitchNode: Try to generate entanglement | ||
| ClientN->>+SwitchNode: Try to generate entanglement | ||
| end | ||
| SwitchNode->>SwitchNode: Run fusions with successful clients | ||
| par Send Measurement Outcomes | ||
| SwitchNode-->>-Client1: Send measurement outcomes | ||
| SwitchNode-->>-ClientN: Send measurement outcomes | ||
| end | ||
| par Apply Corrections (No time cost) | ||
| Client1->>Client1: Apply correction gates | ||
| ClientN->>ClientN: Apply correction gates | ||
| end | ||
| loop Check Fusion Status (No time cost) | ||
| SwitchNode->>SwitchNode: Check if all clients are fused | ||
| alt All clients fused | ||
| SwitchNode->>SwitchNode: Measure piecemaker | ||
| SwitchNode->>SwitchNode: Compute fidelity to GHZ state | ||
| SwitchNode->>Log: Log fidelity and time [END OF PROTOCOL] | ||
| else | ||
| SwitchNode->>SwitchNode: Keep checking | ||
| end | ||
| end | ||
| ``` | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. check the readme of https://github.com/QuantumSavory/QuantumSavory.jl/tree/master/examples/simpleswitch and https://github.com/QuantumSavory/QuantumSavory.jl/tree/master/examples/state_explorer to add similar structural components like a spelled out link to docs and a link to live example (just make up one in the same style, e.g. areweentagledyet...../PICK_A_NAME) -- I will make sure it runs by the time we merge this |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| # Live visualization of the piecemaker switch protocol | ||
| include("setup.jl") | ||
|
|
||
| using Base.Threads | ||
| using WGLMakie | ||
| WGLMakie.activate!() | ||
|
|
||
| using Bonito | ||
| using Markdown | ||
| const custom_css = Bonito.DOM.style("ul {list-style: circle !important;}") | ||
|
|
||
| logging = Observable(Point2f[]) # for plotting | ||
|
|
||
| function push_to_logging!(logging::Observable, t::Float64, fidelity::Float64) | ||
| push!(logging[], Point2f(t, fidelity)) | ||
| end | ||
|
|
||
| function prepare_sim(fig::Figure, n::Int, link_success_prob::Float64, mem_depolar_prob::Float64) | ||
|
|
||
| repr = QuantumOpticsRepr() | ||
|
|
||
| decoherence_rate = -log(1 - mem_depolar_prob) | ||
| noise_model = Depolarization(1 / decoherence_rate) | ||
|
|
||
| switch = Register([Qubit() for _ in 1:(n+1)], [repr for _ in 1:(n+1)], [noise_model for _ in 1:(n+1)]) | ||
| clients = [Register([Qubit()], [repr], [noise_model]) for _ in 1:n] | ||
|
|
||
| graph = star_graph(n + 1) | ||
| net = RegisterNet(graph, [switch, clients...]) | ||
| sim = get_time_tracker(net) | ||
|
|
||
| # Attach the network plot to net and capture its obs | ||
| _, ax_net, _, net_obs = registernetplot_axis(fig[1, 2], net) | ||
| ax_net.title = "Network of n=5 users (live Δt = 0.1s)" | ||
| # Fix the visible ranges | ||
| xlims!(ax_net, -15, 15) | ||
| ylims!(ax_net, -15, 15) | ||
| ax_net.aspect = Makie.DataAspect() # keep aspect ratio | ||
| Makie.deregister_interaction!(ax_net, :scrollzoom) # disable zoom and pan interactions | ||
| Makie.deregister_interaction!(ax_net, :dragpan) | ||
|
|
||
| @process PiecemakerProt(sim, n, net, link_success_prob, -1) # set rounds=1 | ||
|
|
||
| return sim, net, net_obs | ||
| end | ||
|
|
||
| # A helper to add parameter sliders to visualizations | ||
| function add_conf_sliders(fig) | ||
| conf = Dict( | ||
| :link_success_prob => 0.5, | ||
| :mem_depolar_prob => 0.1, | ||
| ) | ||
| conf_obs = Observable(conf) | ||
| sg = SliderGrid( | ||
| fig, | ||
| (label = "link success prob", | ||
| range = 0.05:0.05:1.0, format = "{:.2f}", startvalue = conf[:link_success_prob]), | ||
| (label = "mem depolar prob", | ||
| range = 0.05:0.05:1.0, format = "{:.2f}", startvalue = conf[:mem_depolar_prob]), | ||
| width = 300, | ||
| ) | ||
|
|
||
| names = [:link_success_prob, :mem_depolar_prob] | ||
| for (name,slider) in zip(names,sg.sliders) | ||
| on(slider.value) do val | ||
| conf_obs[][name] = val | ||
| end | ||
| end | ||
| conf_obs | ||
| end | ||
|
|
||
| # Serve the Makie app | ||
| landing = Bonito.App() do | ||
|
|
||
| n = 5 # number of clients | ||
|
|
||
| fig = Figure(resolution = (800, 600)) | ||
| ax_fid = Axis(fig[1, 1], xlabel="Δt (time steps)", ylabel="Fidelity to GHZₙ", title="Fidelity") | ||
| scatter!(ax_fid, logging, markersize = 8) | ||
| ylims!(ax_fid, 0, 1.05) | ||
| xlims!(ax_fid, 0, 30) | ||
|
|
||
| running = Observable{Union{Bool,Nothing}}(false) | ||
| fig[2, 1] = buttongrid = GridLayout(tellwidth = false) | ||
| buttongrid[1,1] = b = Makie.Button( | ||
| fig, | ||
| label = @lift($running ? "Running..." : "Run once"), | ||
| height = 30, tellwidth = false, | ||
| ) | ||
|
|
||
| conf_obs = add_conf_sliders(fig[2, 2]) | ||
|
|
||
| on(b.clicks) do _ | ||
| if running[] # ignore while already running | ||
| return | ||
| end | ||
| running[] = true | ||
| @async begin | ||
| try # run the sim | ||
| sim, net, net_obs = prepare_sim(fig, n, conf_obs[][:link_success_prob], conf_obs[][:mem_depolar_prob]) | ||
| t = 0 | ||
| while true | ||
| t += 1 | ||
| if length(logging[]) > 10 | ||
| break | ||
| end | ||
| run(sim, t) | ||
| notify(net_obs) | ||
| notify(logging) | ||
| sleep(0.1) | ||
| end | ||
| finally | ||
| running[] = false | ||
| logging[] = Point2f[] # clear points for next run | ||
| end | ||
| end | ||
| end | ||
|
|
||
| content = md""" | ||
| Pick simulation settings and hit “Run once”. The left panel plots the running fidelity to the target GHZ state; the right panel shows the network state as it evolves over 10 simulation rounds. | ||
|
|
||
| $(fig.scene) | ||
|
|
||
| # GHZ state distribution with a quantum entanglement switch | ||
|
|
||
| This demo simulates 10 rounds of GHZ-state distribution in a star-shaped network with a central switch node and n client nodes. Each client holds one memory qubit locally and one at the switch. The switch has an extra “piecemaker” qubit (slot n+1) that is initialized in the |+⟩ state; it is used to fuse all successful links into an n-party GHZ state. | ||
|
|
||
| What happens during one run: | ||
| - Per time step, the switch attempts to entangle with each client in parallel (success probability set by the slider “link success prob”). | ||
| - When a client<>switch entanglement attempt succeeds, the switch immediately fuses the client’s switch-side qubit with the piecemaker via a CNOT, measures the client qubit in Z, and sends the outcome to the client. The client applies necessary corrections. | ||
| - After all clients have been fused, the piecemaker is measured in X. The first client receives that outcome and applies a Z correction if needed. | ||
| - The current n-qubit state (the clients’ memory qubits) is compared to the ideal GHZₙ target state. The resulting fidelity is plotted as a point on the left over the number of taken time steps Δt. | ||
|
|
||
| Noise model: | ||
| - Memory qubits are subject to depolarizing noise ([`Depolarization`](https://qs.quantumsavory.org/stable/API/#QuantumSavory.Depolarization) background). The slider “mem depolar prob” controls the memory depolarization probability. | ||
|
|
||
| UI guide: | ||
| - Left: fidelity vs simulation time Δt. Points accumulate across runs so you can compare settings. | ||
| - Right: network snapshot. Edges appear when links are established; updates every 0.1s of real time. | ||
| - Sliders: tune link success probability and memory depolarization probability before each run. | ||
| - Button: starts a single run with the current settings. | ||
|
|
||
| NOTE that this is a simplified simulation for demonstration purposes. In particular, it assumes instantaneous gates as well as classical communication. The only time inducing steps are the attempts for heralded entanglement generation (Δt = 1 time step each). | ||
|
|
||
| [Browse or modify the code for this simulation on GitHub.](https://github.com/QuantumSavory/QuantumSavory.jl/tree/master/examples/piecemakerswitch/live_visualization_interactive.jl) | ||
| """ | ||
| return Bonito.DOM.div(Bonito.MarkdownCSS, Bonito.Styling, custom_css, content) | ||
| end; | ||
|
|
||
|
|
||
| isdefined(Main, :server) && close(server); | ||
| port = parse(Int, get(ENV, "QS_GHZSWITCH_PORT", "3000")) | ||
| interface = get(ENV, "QS_GHZSWITCH_IP", "0.0.0.0") # Bind to all interfaces | ||
| proxy_url = get(ENV, "QS_GHZSWITCH_PROXY", "") | ||
| server = Bonito.Server(interface, port; proxy_url); | ||
| Bonito.HTTPServer.start(server) | ||
| Bonito.route!(server, "/" => landing); | ||
|
|
||
|
|
||
| @info "app server is running on http://$(interface):$(port) | proxy_url=`$(proxy_url)`" | ||
|
|
||
| wait(server) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the tests run with a different project.toml file -- in case some tests fail with a missing dependency, probably you just need to add the dependency to the test project.toml
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when I run
julia --project=. runtests.jlintestI get the following error"ERROR: LoadError: UndefVarError:
onchangenot defined inMain.var"##234""There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that might be because of a weird setup for your project environment; we can debug it with
] status