Q2NS dev
ns-3 module
Loading...
Searching...
No Matches
q2nsviz-teleportation-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-teleportation-example.cc
11 * @brief Quantum teleportation of a |+> state from Alice to Bob.
12 *
13 * Timing model (illustrative):
14 * kSingleGate = 100 ns (single-qubit gate)
15 * kTwoQGate = 300 ns (two-qubit gate)
16 * kQDelay = 10 ns (quantum channel propagation, ~2 m fiber)
17 *
18 * Visualization output is written to
19 * examples/example_traces/q2nsviz-teleportation-example.json and can be loaded in the
20 * q2nsviz viewer (src/q2ns/utils/q2nsviz-serve.sh).
21 *
22 * See docs/tutorials/tutorial-00.md for a detailed walkthrough.
23 */
24
25#include "ns3/core-module.h"
26#include "ns3/internet-module.h"
27#include "ns3/network-module.h"
28#include "ns3/point-to-point-module.h"
29#include "ns3/simulator.h"
30
31#include "ns3/q2ns-netcontroller.h"
32#include "ns3/q2ns-qgate.h"
33#include "ns3/q2ns-qnode.h"
34#include "ns3/q2ns-qubit.h"
35
36#include "ns3/q2nsviz-trace-writer.h"
37#include "ns3/q2nsviz-trace.h"
38
39#include <iostream>
40
41using namespace ns3;
42using namespace q2ns;
43
44static const uint16_t kCtrlPort = 9000;
45
46int main(int argc, char** argv) {
47 std::cout << "[DEMO] Quantum teleportation starting\n";
48
49 RngSeedManager::SetSeed(1);
50 RngSeedManager::SetRun(1);
51
52 CommandLine cmd;
53 cmd.Parse(argc, argv);
54
55 TraceWriter::Instance().Open(Q2NS_EXAMPLE_TRACES_DIR "q2nsviz-teleportation-example.json");
56
57 Time::SetResolution(Time::NS);
58
59 // --- Create quantum network ---
60 NetController net;
61
62 auto alice = net.CreateNode();
63 auto bob = net.CreateNode();
64
65 // --- Timing constants ---
66 // Values are illustrative and platform-neutral (see file header for ranges).
67 const Time kSingleGate = NanoSeconds(100); // single-qubit gate
68 const Time kTwoQGate = NanoSeconds(300); // two-qubit gate
69 const Time kQDelay = NanoSeconds(10); // quantum link propagation (~2 m fiber)
70 const Time kClassical = kQDelay; // classical propagation = quantum (~2 m fiber)
71
72 // Quantum link: Alice <-> Bob
73 auto ch = net.InstallQuantumLink(alice, bob);
74 ch->SetAttribute("Delay", TimeValue(kQDelay));
75
76 TraceCreateNode("Alice", 25, 25);
77 TraceCreateNode("Bob", 75, 25);
78 TraceCreateChannel("Alice", "Bob", "quantum");
79
80 // --- Classical network (UDP for correction bits) ---
81 InternetStackHelper internet;
82 internet.Install(alice);
83 internet.Install(bob);
84
85 PointToPointHelper p2p;
86 p2p.SetDeviceAttribute("DataRate", StringValue("100Mbps"));
87 p2p.SetChannelAttribute("Delay", StringValue("10ns"));
88 NetDeviceContainer devices = p2p.Install(StaticCast<Node>(alice), StaticCast<Node>(bob));
89
90 Ipv4AddressHelper ip;
91 ip.SetBase("10.1.1.0", "255.255.255.0");
92 auto ifs = ip.Assign(devices);
93 Ipv4GlobalRoutingHelper::PopulateRoutingTables();
94 TraceCreateChannel("Alice", "Bob", "classical");
95
96 // --- Sockets ---
97 Ptr<Socket> bobRxSocket = Socket::CreateSocket(bob, UdpSocketFactory::GetTypeId());
98 bobRxSocket->Bind(InetSocketAddress(Ipv4Address::GetAny(), kCtrlPort));
99
100 Ptr<Socket> aliceTxSocket = Socket::CreateSocket(alice, UdpSocketFactory::GetTypeId());
101 aliceTxSocket->Connect(InetSocketAddress(ifs.GetAddress(1), kCtrlPort));
102
103 // --- Bob's shared context (filled by quantum + classical callbacks) ---
104 struct BobCtx {
105 std::shared_ptr<Qubit> eprB;
106 bool qubitArrived = false;
107 bool bitsArrived = false;
108 int m1 = 0; // BSM bit 1: Z-correction coefficient
109 int m2 = 0; // BSM bit 2: X-correction coefficient
110 };
111 BobCtx bobCtx;
112
113 // Local helper: apply corrections and verify once both streams have arrived.
114 auto tryCorrections = [&]() {
115 if (!bobCtx.qubitArrived || !bobCtx.bitsArrived)
116 return;
117
118Trace("Bob applies Pauli corrections Z^m1=", bobCtx.m1, " X^m2=", bobCtx.m2);
119
120 // Apply Z correction (if needed) as an explicit gate step
121 if (bobCtx.m1) {
122 bob->Apply(gates::Z(), {bobCtx.eprB});
123 TraceNodeText("Bob", "Z correction applied (m1=1)");
124 } else {
125 TraceNodeText("Bob", "Z correction skipped (m1=0)");
126 }
127
128 // Apply X correction (if needed) as an explicit gate step
129 if (bobCtx.m2) {
130 bob->Apply(gates::X(), {bobCtx.eprB});
131 TraceNodeText("Bob", "X correction applied (m2=1)");
132 } else {
133 TraceNodeText("Bob", "X correction skipped (m2=0)");
134 }
135
136 // Teleportation complete: bob_epr now holds the teleported psi state.
137 TraceNodeText("Bob", "Teleportation complete - eprB holds psi state");
138
139 // Verify: |+> -> X-measurement should always yield 0
140 Trace("Bob verifies teleported state (X-basis)");
141 int mx = bob->Measure(bobCtx.eprB, Basis::X);
142 TraceMeasure("bob_epr", kSingleGate, "X");
143 TraceRemoveQubit("bob_epr", "discarded");
144 TraceNodeText("Bob", StrCat("X-measure: ", mx, " (expected 0 -> |+> received)"));
145 std::cout << "[VERIFY] Bob's X-measure: " << mx << " (expected 0)\n";
146
147 Simulator::Stop();
148 };
149
150 // Bob's quantum receive callback: eprB has arrived from Alice.
151 bob->SetRecvCallback([&](std::shared_ptr<Qubit> q) {
152 Trace("Bob receives eprB");
153 bobCtx.eprB = q;
154 bobCtx.qubitArrived = true;
155 TraceNodeText("Bob", "eprB arrived - half of Bell pair received");
156 std::cout << "[B][quantum] eprB arrived at t=" << Simulator::Now().GetNanoSeconds() << " ns\n";
157 tryCorrections();
158 });
159
160 // Bob's classical receive callback: correction bits have arrived from Alice.
161 bobRxSocket->SetRecvCallback([&](Ptr<Socket> sock) {
162 Address from;
163 while (Ptr<Packet> p = sock->RecvFrom(from)) {
164 uint8_t bits[2] = {0, 0};
165 p->CopyData(bits, 2);
166 bobCtx.m1 = bits[0] & 1;
167 bobCtx.m2 = bits[1] & 1;
168 bobCtx.bitsArrived = true;
169
170 Trace("Bob receives classical corrections m1=", bobCtx.m1, " m2=", bobCtx.m2);
171 TraceNodeText("Bob", StrCat("Corrections received: m1=", bobCtx.m1, " m2=", bobCtx.m2));
172 std::cout << "[B][CTRL] Corrections arrived: m1=" << bobCtx.m1 << " m2=" << bobCtx.m2 << "\n";
173 TraceRemoveCbit("m1");
174 TraceRemoveCbit("m2");
175 tryCorrections();
176 }
177 });
178
179 // ---------------------------------------------------------------------------
180 // Phase 1: Entanglement preparation and distribution
181 // ---------------------------------------------------------------------------
182 Simulator::Schedule(MicroSeconds(1), [&]() {
183 Trace("Phase 1: Alice creates eprA and eprB");
184 TraceNodeText("Alice", "Phase 1: preparing Bell pair");
185
186 auto eprA = alice->CreateQubit();
187 auto eprB = alice->CreateQubit();
188 TraceCreateQubit("Alice", "alice_epr");
189 TraceCreateQubit("Alice", "bob_epr");
190 std::cout << "[A] eprA, eprB created in |0>\n";
191
192 // H on eprA
193 Simulator::Schedule(kSingleGate, [&, eprA, eprB]() {
194 Trace("Alice applies H to eprA");
195 alice->Apply(gates::H(), {eprA});
196 TraceNodeText("Alice", "H(eprA)");
197 std::cout << "[A] H applied to eprA\n";
198
199 // + 400 ns: CNOT(eprA, eprB) -> |Phi+>
200 Simulator::Schedule(kTwoQGate, [&, eprA, eprB]() {
201 Trace("Alice applies CNOT(eprA, eprB) -> Bell pair |Phi+>");
202 alice->Apply(gates::CNOT(), {eprA, eprB});
203 TraceEntangle({"alice_epr", "bob_epr"}, kTwoQGate);
204 TraceNodeText("Alice", "CNOT(eprA, eprB): Bell pair |Phi+> ready");
205 std::cout << "[A] Bell pair |Phi+> prepared\n";
206
207 // Send eprB to Bob
208 Simulator::Schedule(kSingleGate, [&, eprA, eprB]() {
209 Trace("Alice sends eprB to Bob");
210 TraceSendQubit("bob_epr", "Alice", "Bob", Simulator::Now(),
211 Simulator::Now() + kQDelay);
212 bool ok = alice->Send(eprB, bob->GetId());
213 TraceNodeText("Alice", "eprB sent - in transit to Bob (+10ns)");
214 std::cout << "[A][quantum] eprB sent: " << (ok ? "ok" : "failed") << "\n";
215 // eprA is retained at Alice for the BSM in Phase 2.
216
217 // ---------------------------------------------------------------
218 // Phase 2: Teleportation
219 // ---------------------------------------------------------------
220 Simulator::Schedule(MicroSeconds(2), [&, eprA]() { // absolute T = 3 us
221 Trace("Phase 2: Teleportation begins");
222 TraceNodeText("Alice", "Phase 2: teleportation (entanglement pre-shared)");
223
224 auto psi = alice->CreateQubit();
225 TraceCreateQubit("Alice", "psi");
226 std::cout << "[A] psi created in |0>\n";
227
228 // prepare |+> (the state to teleport)
229 Simulator::Schedule(kSingleGate, [&, eprA, psi]() {
230 Trace("Alice applies H to psi -> |+> (state to teleport)");
231 alice->Apply(gates::H(), {psi});
232 TraceNodeText("Alice", "H(psi): state to teleport is |+>");
233 std::cout << "[A] psi prepared as |+>\n";
234
235 // BSM step 1 - CNOT(psi, eprA)
236 Simulator::Schedule(kTwoQGate, [&, eprA, psi]() {
237 Trace("Alice BSM step 1: CNOT(psi, eprA)");
238 alice->Apply(gates::CNOT(), {psi, eprA});
239 TraceNodeText("Alice", "BSM step 1: CNOT(psi, eprA)");
240 std::cout << "[A][BSM] CNOT(psi, eprA) applied\n";
241
242 // BSM step 2 - H(psi)
243 Simulator::Schedule(kSingleGate, [&, eprA, psi]() {
244 Trace("Alice BSM step 2: H(psi)");
245 alice->Apply(gates::H(), {psi});
246 TraceNodeText("Alice", "BSM step 2: H(psi)");
247 std::cout << "[A][BSM] H(psi) applied\n";
248
249 // BSM step 3 - Z-measure psi and eprA
250 Simulator::Schedule(kSingleGate, [&, eprA, psi]() {
251 Trace("Alice BSM step 3: Z-measure psi and eprA");
252 TraceMeasure("psi", kSingleGate);
253 TraceMeasure("alice_epr", kSingleGate);
254
255 int m1 = alice->Measure(psi); // Z-basis -> Z correction at Bob
256 int m2 = alice->Measure(eprA); // Z-basis -> X correction at Bob
257
258 Trace("BSM outcome: m1=", m1, " m2=", m2);
259 TraceNodeText("Alice", StrCat("BSM complete: m1=", m1, " m2=", m2));
260 std::cout << "[A][BSM] m1=" << m1 << " m2=" << m2 << "\n";
261
262 // Send classical corrections to Bob - tracked as classical bits
263 TraceCreateCbit("Alice", "m1");
264 TraceCreateCbit("Alice", "m2");
265 uint8_t corrBits[2] = {(uint8_t) (m1 & 1), (uint8_t) (m2 & 1)};
266 aliceTxSocket->Send(Create<Packet>(corrBits, 2));
267 TraceSendCbit("m1", "Alice", "Bob", Simulator::Now(), Simulator::Now() + kClassical);
268 TraceSendCbit("m2", "Alice", "Bob", Simulator::Now(), Simulator::Now() + kClassical);
269 TraceSendPacket("Alice", "Bob", Simulator::Now(), Simulator::Now() + kClassical,
270 StrCat("Corrections m1=", m1, " m2=", m2), "udp");
271 TraceNodeText("Alice", StrCat("Corrections sent: m1=", m1, " m2=", m2));
272 std::cout << "[A][CTRL] Corrections sent (~5 us delay)\n";
273
274 // psi and eprA are consumed by BSM measurement
275 TraceRemoveQubit("psi", "discarded");
276 TraceRemoveQubit("alice_epr", "discarded");
277 });
278 });
279 });
280 });
281 });
282 });
283 });
284 });
285 });
286
287 // --- Run simulation ---
288 Simulator::Stop(MilliSeconds(100));
289 Simulator::Run();
290 Simulator::Destroy();
291
293
294 std::cout << "[DONE] Quantum teleportation finished\n";
295 return 0;
296}
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.
QGate X(ns3::Time d=ns3::Seconds(0))
Return the Pauli-X gate descriptor.
Definition q2ns-qgate.h:356
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
QGate Z(ns3::Time d=ns3::Seconds(0))
Return the Pauli-Z gate descriptor.
Definition q2ns-qgate.h:374
int main()
uint8_t m2
uint8_t m1
static const uint16_t kCtrlPort
void TraceRemoveQubit(const std::string &bitLabel, const std::string &reason="discarded", uint64_t t_ns=NowNs())
std::string StrCat(Ts &&... parts)
void TraceSendCbit(const std::string &bitLabel, const std::string &from, const std::string &to, uint64_t t0_ns, uint64_t t1_ns)
void Trace(const std::string &text)
void TraceSendQubit(const std::string &bitLabel, const std::string &from, const std::string &to, uint64_t t0_ns, uint64_t t1_ns)
void TraceCreateQubit(const std::string &node, const std::string &bitLabel)
void TraceNodeText(const std::string &node, const std::string &text)
void TraceEntangle(const std::vector< std::string > &bits)
void TraceRemoveCbit(const std::string &bitLabel, uint64_t t_ns=NowNs())
void TraceMeasure(const std::string &bitLabel, const std::string &base="Z")
void TraceCreateCbit(const std::string &node, const std::string &bitLabel)
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 TraceSendPacket(const std::string &from, const std::string &to, uint64_t t0_ns, uint64_t t1_ns, const std::string &label, const std::string &protocol="")