Q2NS dev
ns-3 module
Loading...
Searching...
No Matches
q2nsviz-ghz-distribution-example.cc
Go to the documentation of this file.
1/*-----------------------------------------------------------------------------
2 * Q2NS - Quantum Network Simulator
3 * Copyright (c) 2026 quantuminternet.it
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *---------------------------------------------------------------------------*/
9/**
10 * @file q2nsviz-ghz-distribution-example.cc
11 * @brief GHZ state generation and distribution across 4 nodes.
12 *
13 * Node1 locally prepares a 4-qubit GHZ state:
14 *
15 * |GHZ> = (|0000> + |1111>) / sqrt(2)
16 *
17 * using a Hadamard gate on q0 followed by three sequential CNOT(q0, qi) for
18 * i in {1,2,3} (serialized because all share q0 as control). It then keeps
19 * q0 and distributes q1->Node2, q2->Node3, q3->Node4 over quantum links,
20 * completing the shared entangled resource.
21 *
22 * Timing model (illustrative, platform-neutral):
23 * kSingleGate = 100 ns (single-qubit gate)
24 * kTwoQGate = 300 ns (two-qubit gate)
25 * kQDelay = 100 ns (quantum channel propagation, ~20 m fiber)
26 *
27 * Visualization output is written to
28 * examples/example_traces/q2nsviz-ghz-distribution-example.json and can be loaded in the
29 * q2nsviz viewer (src/q2ns/utils/q2nsviz-serve.sh).
30 *
31 * See docs/tutorials/tutorial-00.md for a detailed walkthrough.
32 */
33
34#include "ns3/core-module.h"
35#include "ns3/internet-module.h"
36#include "ns3/network-module.h"
37#include "ns3/point-to-point-module.h"
38#include "ns3/simulator.h"
39
40#include "ns3/q2ns-netcontroller.h"
41#include "ns3/q2ns-qgate.h"
42#include "ns3/q2ns-qnode.h"
43#include "ns3/q2ns-qubit.h"
44
45#include "ns3/q2nsviz-trace-writer.h"
46#include "ns3/q2nsviz-trace.h"
47
48#include <atomic>
49#include <iostream>
50
51using namespace ns3;
52using namespace q2ns;
53
54static const uint16_t kAckPort = 9100;
55
56int main(int argc, char** argv) {
57 std::cout << "[DEMO] GHZ state distribution (4 nodes) starting\n";
58
59 RngSeedManager::SetSeed(1);
60 RngSeedManager::SetRun(1);
61
62 CommandLine cmd;
63 cmd.Parse(argc, argv);
64
65 // Visualization output
66 TraceWriter::Instance().Open("examples/example_traces/q2nsviz-ghz-distribution-example.json");
67
68 Trace("GHZ State Distribution with 4 nodes");
69
70 Time::SetResolution(Time::NS);
71
72 NetController net;
73 net.SetQStateBackend(QStateBackend::Stab);
74
75 // --- Nodes ---
76 Ptr<QNode> node1 = net.CreateNode();
77 Ptr<QNode> node2 = net.CreateNode();
78 Ptr<QNode> node3 = net.CreateNode();
79 Ptr<QNode> node4 = net.CreateNode();
80
81 TraceCreateNode("Node1", 85, 50);
82 TraceCreateNode("Node2", 50, 85);
83 TraceCreateNode("Node3", 15, 50);
84 TraceCreateNode("Node4", 49, 15);
85
86 // --- Timing constants ---
87 // Values are illustrative
88 const Time kSingleGate = NanoSeconds(100); // single-qubit gate
89 const Time kTwoQGate = NanoSeconds(300); // two-qubit gate
90 const Time kQDelay = NanoSeconds(100); // quantum link propagation (~20 m fiber)
91 const Time kClassical = kQDelay; // classical propagation = quantum (~20 m fiber)
92
93 // --- Quantum links (star from Node1) ---
94 auto ch12 = net.InstallQuantumLink(node1, node2);
95 auto ch13 = net.InstallQuantumLink(node1, node3);
96 auto ch14 = net.InstallQuantumLink(node1, node4);
97 ch12->SetAttribute("Delay", TimeValue(kQDelay));
98 ch13->SetAttribute("Delay", TimeValue(kQDelay));
99 ch14->SetAttribute("Delay", TimeValue(kQDelay));
100
101 // Trace star topology channels (only the physical links that carry this protocol)
102 TraceCreateChannel("Node1", "Node2", "quantum");
103 TraceCreateChannel("Node1", "Node2", "classical");
104 TraceCreateChannel("Node1", "Node3", "quantum");
105 TraceCreateChannel("Node1", "Node3", "classical");
106 TraceCreateChannel("Node1", "Node4", "quantum");
107 TraceCreateChannel("Node1", "Node4", "classical");
108
109 // --- Classical network (star p2p from Node1) ---
110 InternetStackHelper internet;
111 internet.Install(node1);
112 internet.Install(node2);
113 internet.Install(node3);
114 internet.Install(node4);
115
116 PointToPointHelper p2p;
117 p2p.SetDeviceAttribute("DataRate", StringValue("100Mbps"));
118 p2p.SetChannelAttribute("Delay", StringValue("100ns"));
119
120 Ipv4AddressHelper ipv4;
121
122 ipv4.SetBase("10.1.1.0", "255.255.255.0");
123 auto ifs12 = ipv4.Assign(p2p.Install(node1, node2));
124
125 ipv4.SetBase("10.1.2.0", "255.255.255.0");
126 auto ifs13 = ipv4.Assign(p2p.Install(node1, node3));
127
128 ipv4.SetBase("10.1.3.0", "255.255.255.0");
129 auto ifs14 = ipv4.Assign(p2p.Install(node1, node4));
130
131 Ipv4GlobalRoutingHelper::PopulateRoutingTables();
132
133 // ---------------------------------------------------------------------------
134 // UDP ACK infrastructure
135 // Each of Node2/3/4 sends a 1-byte ACK to Node1 upon qubit arrival.
136 // Node1 aggregates them and fires a final summary trace when all three arrive.
137 // ---------------------------------------------------------------------------
138 // Note that ifs12.GetAddress(0) is Node1's IP on the 1-2 subnet; with global routing all
139 // remote nodes can reach it regardless of which subnet they are on.
140 const Ipv4Address kNode1Addr = ifs12.GetAddress(0);
141
142 // Node1 ACK-receive socket
143 auto node1AckRx = Socket::CreateSocket(node1, UdpSocketFactory::GetTypeId());
144 node1AckRx->Bind(InetSocketAddress(Ipv4Address::GetAny(), kAckPort));
145 int acksReceived = 0;
146 node1AckRx->SetRecvCallback([&](Ptr<Socket> sock) {
147 Address from;
148 while (sock->RecvFrom(from)) {
149 ++acksReceived;
150 TraceNodeText("Node1", StrCat("ACK received (", acksReceived, "/3 GHZ nodes confirmed)"));
151 std::cout << "[NODE1] ACK " << acksReceived << "/3 received\n";
152 if (acksReceived == 3) {
153 Trace("GHZ resource confirmed by all remote nodes");
154 TraceSetBitColor("q0", "#44AA99");
155 }
156 }
157 });
158
159 // Pre-create one ACK transmit socket per remote node (connected before simulation).
160 auto node2TxSock = Socket::CreateSocket(node2, UdpSocketFactory::GetTypeId());
161 node2TxSock->Connect(InetSocketAddress(kNode1Addr, kAckPort));
162
163 auto node3TxSock = Socket::CreateSocket(node3, UdpSocketFactory::GetTypeId());
164 node3TxSock->Connect(InetSocketAddress(ifs13.GetAddress(0), kAckPort));
165
166 auto node4TxSock = Socket::CreateSocket(node4, UdpSocketFactory::GetTypeId());
167 node4TxSock->Connect(InetSocketAddress(ifs14.GetAddress(0), kAckPort));
168
169 // Node2 receive callback: q1 arrives, send ACK to Node1
170 node2->SetRecvCallback([&](std::shared_ptr<Qubit> q) {
171 TraceSetBitColor(q->GetLabel(), "#90EE90");
172 TraceNodeText("Node2", StrCat("GHZ qubit ", q->GetLabel(), " arrived"));
173 std::cout << "[NODE2] " << q->GetLabel() << " arrived\n";
174 node2TxSock->Send(Create<Packet>(1));
175 TraceSendPacket("Node2", "Node1", Simulator::Now(), Simulator::Now() + kClassical,
176 StrCat("ACK: ", q->GetLabel(), " received"));
177 });
178
179 // Node3 receive callback: q2 arrives, send ACK to Node1
180 node3->SetRecvCallback([&](std::shared_ptr<Qubit> q) {
181 TraceSetBitColor(q->GetLabel(), "#90EE90");
182 TraceNodeText("Node3", StrCat("GHZ qubit ", q->GetLabel(), " arrived"));
183 std::cout << "[NODE3] " << q->GetLabel() << " arrived\n";
184 node3TxSock->Send(Create<Packet>(1));
185 TraceSendPacket("Node3", "Node1", Simulator::Now(), Simulator::Now() + kClassical,
186 StrCat("ACK: ", q->GetLabel(), " received"));
187 });
188
189 // Node4 receive callback: q3 arrives, send ACK to Node1
190 node4->SetRecvCallback([&](std::shared_ptr<Qubit> q) {
191 TraceSetBitColor(q->GetLabel(), "#90EE90");
192 TraceNodeText("Node4", StrCat("GHZ qubit ", q->GetLabel(), " arrived"));
193 std::cout << "[NODE4] " << q->GetLabel() << " arrived\n";
194 node4TxSock->Send(Create<Packet>(1));
195 TraceSendPacket("Node4", "Node1", Simulator::Now(), Simulator::Now() + kClassical,
196 StrCat("ACK: ", q->GetLabel(), " received"));
197 });
198
199 // ---------------------------------------------------------------------------
200 // Simulation events
201 // ---------------------------------------------------------------------------
202 Simulator::Schedule(MicroSeconds(1), [=] {
203 auto q0 = node1->CreateQubit("q0");
204 auto q1 = node1->CreateQubit("q1");
205 auto q2 = node1->CreateQubit("q2");
206 auto q3 = node1->CreateQubit("q3");
207
208 TraceCreateBit("Node1", "q0", "quantum", "#88CCEE");
209 TraceCreateBit("Node1", "q1", "quantum", "#88CCEE");
210 TraceCreateBit("Node1", "q2", "quantum", "#88CCEE");
211 TraceCreateBit("Node1", "q3", "quantum", "#88CCEE");
212 TraceNodeText("Node1", "q0-q3 initialized");
213
214 // -- Prepare GHZ state on Node1 ---
215 Simulator::Schedule(kSingleGate, [=] {
216 Trace("Applying H to q0");
217 node1->Apply(q2ns::gates::H(), {q0});
218 TraceSetBitColor("q0", "#BC71EB");
219 TraceNodeText("Node1", "H(q0)");
220
221 Simulator::Schedule(kTwoQGate, [=] {
222 Trace("CNOT(q0, q1)");
223 node1->Apply(q2ns::gates::CNOT(), {q0, q1});
224 TraceEntangle({"q0", "q1"}, kTwoQGate);
225 TraceNodeText("Node1", "CNOT(q0, q1)");
226
227 Simulator::Schedule(kTwoQGate, [=] {
228 Trace("CNOT(q0, q2)");
229 node1->Apply(q2ns::gates::CNOT(), {q0, q2});
230 TraceEntangle({"q0", "q2"}, kTwoQGate);
231 TraceNodeText("Node1", "CNOT(q0, q2)");
232
233 Simulator::Schedule(kTwoQGate, [=] {
234 Trace("CNOT(q0, q3) - GHZ state ready");
235 node1->Apply(q2ns::gates::CNOT(), {q0, q3});
236 TraceEntangle({"q0", "q3"}, kTwoQGate);
237 TraceNodeText("Node1", "GHZ state ready");
238 std::cout << "[NODE1] GHZ state prepared: (|0000> + |1111>)/sqrt(2)\n";
239
240 // Distribute qubits to nodes
241 // Sends are staggered by 50 ns each for visual clarity
242 // (three independent quantum channels, could be simultaneous physically).
243 Simulator::Schedule(kSingleGate, [=] {
244 Trace("Distributing GHZ qubits to nodes");
245 TraceNodeText("Node1", "Sending q1/q2/q3 to nodes 2/3/4");
246
247 const Time kSendGap = NanoSeconds(50);
248 auto t0 = Simulator::Now();
249
250 node1->Send(q1, node2->GetId());
251 TraceSendBit("q1", "Node1", "Node2", "quantum", t0, t0 + kQDelay);
252
253 Simulator::Schedule(kSendGap, [=] {
254 auto t1 = Simulator::Now();
255 node1->Send(q2, node3->GetId());
256 TraceSendBit("q2", "Node1", "Node3", "quantum", t1, t1 + kQDelay);
257
258 Simulator::Schedule(kSendGap, [=] {
259 auto t2 = Simulator::Now();
260 node1->Send(q3, node4->GetId());
261 TraceSendBit("q3", "Node1", "Node4", "quantum", t2, t2 + kQDelay);
262 TraceNodeText("Node1", "q1/q2/q3 in transit - awaiting ACKs");
263
264 Simulator::Schedule(kQDelay + NanoSeconds(50), [=] {
265 Trace("GHZ quantum distribution complete - waiting for classical ACKs");
266 std::cout << "[NODE1] GHZ qubits in flight, waiting for ACKs\n";
267 });
268 });
269 });
270 });
271 });
272 });
273 });
274 });
275 });
276
277 Simulator::Stop(MilliSeconds(1));
278 Simulator::Run();
279 Simulator::Destroy();
280
282 std::cout << "[DONE] GHZ distribution finished\n";
283 return 0;
284}
static TraceWriter & Instance()
void Open(const std::string &path)
Main user-facing facade for creating and configuring a quantum network.
ns3::Ptr< QNode > CreateNode(const std::string &label="")
Create a QNode with an optional human-readable label.
ns3::Ptr< QChannel > InstallQuantumLink(ns3::Ptr< QNode > a, ns3::Ptr< QNode > b)
Install a duplex quantum link between two nodes.
void SetQStateBackend(QStateBackend b)
Set the default backend used for newly created quantum states.
QGate H(ns3::Time d=ns3::Seconds(0))
Return the Hadamard gate descriptor.
Definition q2ns-qgate.h:383
QGate CNOT(ns3::Time d=ns3::Seconds(0))
Return the CNOT gate descriptor.
Definition q2ns-qgate.h:410
int main()
static const uint16_t kAckPort
std::string StrCat(Ts &&... parts)
void Trace(const std::string &text)
void TraceNodeText(const std::string &node, const std::string &text)
void TraceEntangle(const std::vector< std::string > &bits)
void TraceSendPacket(const std::string &from, const std::string &to, uint64_t t0_ns, uint64_t t1_ns, const std::string &label)
void TraceCreateBit(const std::string &node, const std::string &bitLabel, const std::string &kind, const std::string &color)
void TraceCreateNode(const std::string &label, int xPct, int yPct)
void TraceCreateChannel(const std::string &from, const std::string &to, const std::string &kind)
void TraceSendBit(const std::string &bitLabel, const std::string &from, const std::string &to, const std::string &kind, uint64_t t0_ns, uint64_t t1_ns)
void TraceSetBitColor(const std::string &bitLabel, const std::string &color)