Q2NS dev
ns-3 module
Loading...
Searching...
No Matches
q2ns-5-noisy-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 q2ns-5-noisy-teleportation-example.cc
11 * @brief Teleportation experiment with UDP and Bob-side memory noise
12 *
13 * Demonstrates:
14 * - quantum teleportation over a quantum link
15 * - classical correction delivery over UDP
16 * - distance-dependent propagation delay
17 * - Bob-side depolarizing noise while waiting for classical corrections
18 * - repeated trials with fidelity / latency statistics
19 *
20 * Tunable parameters:
21 * --distanceKm Alice-Bob distance in km
22 * --TDepMs Bob memory characteristic time in ms (0 => ideal memory)
23 * --trials number of repeated trials
24 * --verbose print per-trial details
25 *
26 * Example:
27 * ./ns3 run q2ns-5-noisy-teleportation-example -- --distanceKm=50 --TDepMs=5 --trials=20
28 *--verbose=1
29 *---------------------------------------------------------------------------*/
30
31#include "ns3/core-module.h"
32#include "ns3/internet-module.h"
33#include "ns3/network-module.h"
34#include "ns3/point-to-point-module.h"
35#include "ns3/simulator.h"
36
37#include "ns3/q2ns-analysis.h"
38#include "ns3/q2ns-netcontroller.h"
39#include "ns3/q2ns-qmap.h"
40#include "ns3/q2ns-qnode.h"
41#include "ns3/q2ns-qubit.h"
42
43#include <algorithm>
44#include <cmath>
45#include <cstdint>
46#include <iomanip>
47#include <iostream>
48#include <limits>
49#include <memory>
50#include <numeric>
51#include <vector>
52
53using namespace ns3;
54using namespace q2ns;
55
56namespace {
57
59 std::vector<double> xs;
60
61 void Add(double x) {
62 xs.push_back(x);
63 }
64
65 double Mean() const {
66 if (xs.empty()) {
67 return 0.0;
68 }
69 return std::accumulate(xs.begin(), xs.end(), 0.0) / static_cast<double>(xs.size());
70 }
71
72 double StdDev() const {
73 if (xs.size() < 2) {
74 return 0.0;
75 }
76 const double mean = Mean();
77 double acc = 0.0;
78 for (double x : xs) {
79 const double d = x - mean;
80 acc += d * d;
81 }
82 return std::sqrt(acc / static_cast<double>(xs.size() - 1));
83 }
84
85 double Median() const {
86 if (xs.empty()) {
87 return 0.0;
88 }
89 std::vector<double> tmp = xs;
90 std::sort(tmp.begin(), tmp.end());
91 const size_t n = tmp.size();
92 if (n % 2 == 1) {
93 return tmp[n / 2];
94 }
95 return 0.5 * (tmp[n / 2 - 1] + tmp[n / 2]);
96 }
97};
98
99struct BobInfo {
100 std::shared_ptr<Qubit> qRemote;
101 bool qubitArrived = false;
102 bool bitsArrived = false;
103 int m1 = 0;
104 int m2 = 0;
105 Time tQubitArrive = Seconds(0);
106 Time tBitsArrive = Seconds(0);
107 bool done = false;
108 double finalFidelity = std::numeric_limits<double>::quiet_NaN();
109 double completionMs = std::numeric_limits<double>::quiet_NaN();
110};
111
112void TryCorrections(Ptr<QNode> bob, NetController& net, BobInfo& info, Ptr<DepolarizingQMap> depol,
113 Ptr<UniformRandomVariable> u, std::shared_ptr<Qubit> qIdealPlus, Time tStart,
114 bool verbose) {
115 if (info.done || !info.qubitArrived || !info.bitsArrived) {
116 return;
117 }
118
119 // Bob's qubit sits in memory from quantum arrival until the classical bits arrive.
120 const Time holdTime = info.tBitsArrive - info.tQubitArrive;
121
122 QMapContext ctx;
123 ctx.elapsedTime = holdTime;
124
125 QMapInstance instance = depol->Sample(u, ctx);
126 instance(*bob, info.qRemote);
127
128 // Standard teleportation correction: X^m2 Z^m1
129 if (info.m2) {
130 bob->Apply(gates::X(), {info.qRemote});
131 }
132 if (info.m1) {
133 bob->Apply(gates::Z(), {info.qRemote});
134 }
135
136 const auto finalState = net.GetState(info.qRemote);
137 const auto idealState = net.GetState(qIdealPlus);
138
139 info.finalFidelity = q2ns::analysis::Fidelity(*finalState, *idealState);
140 info.completionMs = (Simulator::Now() - tStart).GetSeconds() * 1000.0;
141 info.done = true;
142
143 if (verbose) {
144 std::cout << "[B] corrections applied"
145 << " hold_ms=" << std::fixed << std::setprecision(3)
146 << holdTime.GetSeconds() * 1000.0 << " fidelity=" << std::setprecision(4)
147 << info.finalFidelity << "\n";
148 }
149
150 Simulator::Stop();
151}
152
154 double fidelity = std::numeric_limits<double>::quiet_NaN();
155 double completionMs = std::numeric_limits<double>::quiet_NaN();
156};
157
158TrialResult RunOnce(double distanceKm, double TDepMs, bool verbose) {
159 const uint16_t port = 9000;
160
161 // Approximate propagation in fiber: 5 microseconds / km
162 const Time qDelay = MicroSeconds(static_cast<int64_t>(std::llround(5.0 * distanceKm)));
163 const Time cDelay = MicroSeconds(static_cast<int64_t>(std::llround(5.0 * distanceKm)));
164
165 BobInfo bobInfo;
166 Time tStart = Seconds(0);
167
168 NetController net;
169 net.SetQStateBackend(QStateBackend::Ket);
170
171 auto A = net.CreateNode();
172 auto B = net.CreateNode();
173
174 // Reference node for the ideal |+> state
175 auto ref = net.CreateNode();
176 auto qIdealPlus = ref->CreateQubit();
177 ref->Apply(gates::H(), {qIdealPlus});
178
179 // Bob memory-noise map: p = 1 - exp(-t / Tdep)
180 auto depol = CreateObject<DepolarizingQMap>();
181 if (TDepMs > 0.0) {
182 const double ratePerSecond = 1000.0 / TDepMs; // TDepMs is in ms
183 depol->SetAttribute("Rate", DoubleValue(ratePerSecond));
184 } else {
185 depol->SetAttribute("Probability", DoubleValue(0.0));
186 }
187
188 auto u = CreateObject<UniformRandomVariable>();
189
190 // Quantum link
191 auto ch = net.InstallQuantumLink(A, B);
192 ch->SetAttribute("Delay", TimeValue(qDelay));
193
194 // Classical UDP link
195 InternetStackHelper internet;
196 internet.Install(A);
197 internet.Install(B);
198
199 PointToPointHelper p2p;
200 p2p.SetDeviceAttribute("DataRate", StringValue("100Mbps"));
201 p2p.SetChannelAttribute("Delay", TimeValue(cDelay));
202 NetDeviceContainer devices = p2p.Install(A, B);
203
204 Ipv4AddressHelper ip;
205 ip.SetBase("10.1.1.0", "255.255.255.0");
206 Ipv4InterfaceContainer interfaces = ip.Assign(devices);
207
208 Ptr<Socket> bobSocket = Socket::CreateSocket(B, UdpSocketFactory::GetTypeId());
209 bobSocket->Bind(InetSocketAddress(Ipv4Address::GetAny(), port));
210
211 Ptr<Socket> aliceSocket = Socket::CreateSocket(A, UdpSocketFactory::GetTypeId());
212 aliceSocket->Connect(InetSocketAddress(interfaces.GetAddress(1), port));
213
214 // Bob's classical receive callback
215 bobSocket->SetRecvCallback(
216 [B, &bobInfo, &net, depol, u, qIdealPlus, &tStart, verbose](Ptr<Socket> socket) {
217 while (Ptr<Packet> packet = socket->Recv()) {
218 uint8_t bytes[2] = {0, 0};
219 const uint32_t n = packet->CopyData(bytes, 2);
220
221 if (n < 2) {
222 continue;
223 }
224
225 bobInfo.bitsArrived = true;
226 bobInfo.m1 = bytes[0] & 1;
227 bobInfo.m2 = bytes[1] & 1;
228 bobInfo.tBitsArrive = Simulator::Now();
229
230 if (verbose) {
231 std::cout << "[RECV][classical][B][udp] t=" << std::fixed << std::setprecision(6)
232 << Simulator::Now().GetSeconds() << " s"
233 << " m1=" << bobInfo.m1 << " m2=" << bobInfo.m2 << "\n";
234 }
235
236 TryCorrections(B, net, bobInfo, depol, u, qIdealPlus, tStart, verbose);
237 }
238 });
239
240 // Bob's quantum receive callback
241 B->SetRecvCallback(
242 [B, &bobInfo, &net, depol, u, qIdealPlus, &tStart, verbose](std::shared_ptr<Qubit> q) {
243 bobInfo.qRemote = q;
244 bobInfo.qubitArrived = true;
245 bobInfo.tQubitArrive = Simulator::Now();
246
247 if (verbose) {
248 std::cout << "[RECV][quantum][B] t=" << std::fixed << std::setprecision(6)
249 << Simulator::Now().GetSeconds() << " s\n";
250 }
251
252 TryCorrections(B, net, bobInfo, depol, u, qIdealPlus, tStart, verbose);
253 });
254
255 // Teleportation protocol
256 Simulator::Schedule(NanoSeconds(1), [&]() {
257 tStart = Simulator::Now();
258
259 auto [qA, qBRemote] = A->CreateBellPair();
260 const bool ok = A->Send(qBRemote, B->GetId());
261
262 if (verbose) {
263 std::cout << "[SEND][quantum] A->B: " << (ok ? "ok" : "failed") << "\n";
264 }
265
266 auto psi = A->CreateQubit();
267 A->Apply(gates::H(), {psi}); // teleport |+>
268
269 auto [m1, m2] = A->MeasureBell(psi, qA);
270
271 if (verbose) {
272 std::cout << "[A] BSM results: " << m1 << ", " << m2 << "\n";
273 }
274
275 uint8_t bytes[2] = {
276 static_cast<uint8_t>(m1),
277 static_cast<uint8_t>(m2),
278 };
279
280 aliceSocket->Send(Create<Packet>(bytes, 2));
281
282 if (verbose) {
283 std::cout << "[SEND][classical][udp] A->B\n";
284 }
285 });
286
287 Simulator::Stop(Seconds(5));
288 Simulator::Run();
289 Simulator::Destroy();
290
291 TrialResult r;
292 r.fidelity = bobInfo.finalFidelity;
293 r.completionMs = bobInfo.completionMs;
294 return r;
295}
296
297} // namespace
298
299int main(int argc, char* argv[]) {
300 double distanceKm = 50.0;
301 double TDepMs = 5.0;
302 uint32_t trials = 10;
303 uint32_t seed = 1;
304 uint32_t run = 1;
305 bool verbose = false;
306
307 CommandLine cmd;
308 cmd.AddValue("distanceKm", "Distance between Alice and Bob in km", distanceKm);
309 cmd.AddValue("TDepMs", "Bob memory characteristic time in ms (0 => ideal memory)", TDepMs);
310 cmd.AddValue("trials", "Number of repeated trials", trials);
311 cmd.AddValue("seed", "ns-3 RNG seed", seed);
312 cmd.AddValue("run", "ns-3 RNG run number", run);
313 cmd.AddValue("verbose", "Print per-trial details", verbose);
314 cmd.Parse(argc, argv);
315
316 RngSeedManager::SetSeed(seed);
317
318 RunningStats fidelityStats;
319 RunningStats latencyStats;
320
321 if (verbose) {
322 std::cout << "[DEMO] Noisy teleportation experiment starting\n";
323 std::cout << " distanceKm = " << distanceKm << "\n";
324 std::cout << " TDepMs = " << TDepMs << "\n";
325 std::cout << " trials = " << trials << "\n";
326 }
327
328 for (uint32_t t = 0; t < trials; ++t) {
329 RngSeedManager::SetRun(run + t);
330
331 if (verbose) {
332 std::cout << "\n[TRIAL " << (t + 1) << "/" << trials << "]\n";
333 }
334
335 TrialResult r = RunOnce(distanceKm, TDepMs, verbose);
336 fidelityStats.Add(r.fidelity);
337 latencyStats.Add(r.completionMs);
338 }
339
340 std::cout << "\n[RESULT]"
341 << " distance_km=" << std::fixed << std::setprecision(3) << distanceKm
342 << " TDep_ms=" << TDepMs << " trials=" << trials
343 << " fidelity_mean=" << std::setprecision(4) << fidelityStats.Mean()
344 << " fidelity_median=" << fidelityStats.Median()
345 << " fidelity_stddev=" << fidelityStats.StdDev()
346 << " latency_mean_ms=" << std::setprecision(4) << latencyStats.Mean()
347 << " latency_median_ms=" << latencyStats.Median()
348 << " latency_stddev_ms=" << latencyStats.StdDev() << "\n";
349
350 if (verbose) {
351 std::cout << "[DONE] Noisy teleportation experiment finished\n";
352 }
353
354 return 0;
355}
Main user-facing facade for creating and configuring a quantum network.
std::shared_ptr< QState > GetState(const std::shared_ptr< Qubit > &q) const
Convenience helper to get a qubit's current backend state.
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.
double Fidelity(const QState &a, const QState &b)
Compute fidelity between two QState objects of the same backend type.
std::function< void(QNode &, std::shared_ptr< Qubit > &)> QMapInstance
Per-transmission quantum map callable applied to a received qubit.
Definition q2ns-types.h:71
TrialResult RunOnce(double distanceKm, double TDepMs, bool verbose)
void TryCorrections(Ptr< QNode > bob, NetController &net, BobInfo &info, Ptr< DepolarizingQMap > depol, Ptr< UniformRandomVariable > u, std::shared_ptr< Qubit > qIdealPlus, Time tStart, bool verbose)
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 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
Optional per-sample context passed to QMaps.
Definition q2ns-qmap.h:41
ns3::Time elapsedTime
Elapsed time that this map is applied over.
Definition q2ns-qmap.h:42