Q2NS dev
ns-3 module
Loading...
Searching...
No Matches
q2ns-5-noisy-teleportation-advanced-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-advanced-example.cc
11 * @brief Teleportation experiment with UDP/TCP control transport and Bob-side memory noise
12 *
13 * Demonstrates:
14 * - quantum teleportation over a quantum link
15 * - classical correction delivery over UDP or TCP
16 * - receiver setup via PacketSinkHelper
17 * - distance-dependent propagation delay
18 * - Bob-side depolarizing noise while waiting for classical corrections
19 * - repeated trials with fidelity / latency statistics
20 *
21 * Tunable parameters:
22 * --proto udp | tcp
23 * --distanceKm Alice-Bob distance in km
24 * --TDepMs Bob memory characteristic time in ms (0 => ideal memory)
25 * --trials number of repeated trials
26 * --verbose print per-trial details
27 *
28 * Example:
29 * ./ns3 run q2ns-5-noisy-teleportation-advanced-example -- --proto=udp --distanceKm=50 --TDepMs=5
30 *--trials=20 --verbose=1
31 * ./ns3 run q2ns-5-noisy-teleportation-advanced-example -- --proto=tcp --distanceKm=50 --TDepMs=5
32 *--trials=20 --verbose=1
33 *---------------------------------------------------------------------------*/
34
35#include "ns3/applications-module.h"
36#include "ns3/core-module.h"
37#include "ns3/internet-module.h"
38#include "ns3/network-module.h"
39#include "ns3/point-to-point-module.h"
40#include "ns3/simulator.h"
41
42#include "ns3/q2ns-analysis.h"
43#include "ns3/q2ns-netcontroller.h"
44#include "ns3/q2ns-qmap.h"
45#include "ns3/q2ns-qnode.h"
46#include "ns3/q2ns-qubit.h"
47
48#include <algorithm>
49#include <cmath>
50#include <cstdint>
51#include <iomanip>
52#include <iostream>
53#include <limits>
54#include <memory>
55#include <numeric>
56#include <string>
57#include <vector>
58
59using namespace ns3;
60using namespace q2ns;
61
62namespace {
63
65 std::vector<double> xs;
66
67 void Add(double x) {
68 xs.push_back(x);
69 }
70
71 double Mean() const {
72 if (xs.empty()) {
73 return 0.0;
74 }
75 return std::accumulate(xs.begin(), xs.end(), 0.0) / static_cast<double>(xs.size());
76 }
77
78 double StdDev() const {
79 if (xs.size() < 2) {
80 return 0.0;
81 }
82 const double mean = Mean();
83 double acc = 0.0;
84 for (double x : xs) {
85 const double d = x - mean;
86 acc += d * d;
87 }
88 return std::sqrt(acc / static_cast<double>(xs.size() - 1));
89 }
90
91 double Median() const {
92 if (xs.empty()) {
93 return 0.0;
94 }
95 std::vector<double> tmp = xs;
96 std::sort(tmp.begin(), tmp.end());
97 const size_t n = tmp.size();
98 if (n % 2 == 1) {
99 return tmp[n / 2];
100 }
101 return 0.5 * (tmp[n / 2 - 1] + tmp[n / 2]);
102 }
103};
104
105struct BobInfo {
106 std::shared_ptr<Qubit> qRemote;
107 bool qubitArrived = false;
108 bool bitsArrived = false;
109 int m1 = 0;
110 int m2 = 0;
111 Time tQubitArrive = Seconds(0);
112 Time tBitsArrive = Seconds(0);
113 bool done = false;
114 double finalFidelity = std::numeric_limits<double>::quiet_NaN();
115 double completionMs = std::numeric_limits<double>::quiet_NaN();
116};
117
119 double fidelity = std::numeric_limits<double>::quiet_NaN();
120 double completionMs = std::numeric_limits<double>::quiet_NaN();
121};
122
124 Ptr<Packet> pendingPkt;
125 bool sent = false;
126 bool verbose = false;
127};
128
129
130void TryCorrections(Ptr<QNode> bob, NetController& net, BobInfo& info, Ptr<DepolarizingQMap> depol,
131 Ptr<UniformRandomVariable> u, std::shared_ptr<Qubit> qRef, Time tStart,
132 bool verbose) {
133 if (info.done || !info.qubitArrived || !info.bitsArrived) {
134 return;
135 }
136
137 // Bob's qubit sits in memory from quantum arrival until the classical bits arrive.
138 const Time holdTime = info.tBitsArrive - info.tQubitArrive;
139
140 QMapContext ctx;
141 ctx.elapsedTime = holdTime;
142
143 QMapInstance instance = depol->Sample(u, ctx);
144 instance(*bob, info.qRemote);
145
146 // Standard teleportation correction: X^m2 Z^m1
147 if (info.m2) {
148 bob->Apply(gates::X(), {info.qRemote});
149 }
150 if (info.m1) {
151 bob->Apply(gates::Z(), {info.qRemote});
152 }
153
154 const auto finalState = net.GetState(info.qRemote);
155 const auto idealState = net.GetState(qRef);
156
157 info.finalFidelity = q2ns::analysis::Fidelity(*finalState, *idealState);
158 info.completionMs = (Simulator::Now() - tStart).GetSeconds() * 1000.0;
159 info.done = true;
160
161 if (verbose) {
162 std::cout << "[B] corrections applied"
163 << " hold_ms=" << std::fixed << std::setprecision(3)
164 << holdTime.GetSeconds() * 1000.0 << " fidelity=" << std::setprecision(4)
165 << info.finalFidelity << "\n";
166 }
167
168 Simulator::Stop();
169}
170
171
172static void OnControlRxTrace(Ptr<QNode> bob, BobInfo* bobInfo, NetController* net,
173 Ptr<DepolarizingQMap> depol, Ptr<UniformRandomVariable> u,
174 std::shared_ptr<Qubit> qRef, Time* tStart, bool verbose,
175 Ptr<const Packet> packet, const Address&) {
176 uint8_t bytes[2] = {0, 0};
177 const uint32_t n = packet->CopyData(bytes, 2);
178
179 if (n < 2) {
180 return;
181 }
182
183 bobInfo->bitsArrived = true;
184 bobInfo->m1 = bytes[0] & 1;
185 bobInfo->m2 = bytes[1] & 1;
186 bobInfo->tBitsArrive = Simulator::Now();
187
188 if (verbose) {
189 std::cout << "[RECV][classical][B] t=" << std::fixed << std::setprecision(6)
190 << Simulator::Now().GetSeconds() << " s"
191 << " m1=" << bobInfo->m1 << " m2=" << bobInfo->m2 << "\n";
192 }
193
194 TryCorrections(bob, *net, *bobInfo, depol, u, qRef, *tStart, verbose);
195}
196
197static void OnTcpConnectSuccess(std::shared_ptr<TcpSendState> tcpState, Ptr<Socket> s) {
198 if (!tcpState->sent && tcpState->pendingPkt) {
199 s->Send(tcpState->pendingPkt);
200 tcpState->sent = true;
201
202 if (tcpState->verbose) {
203 std::cout << "[SEND][classical][tcp] A->B\n";
204 }
205
206 s->Close();
207 }
208}
209
210static void OnTcpConnectFail(bool verbose, Ptr<Socket> s) {
211 if (verbose) {
212 std::cout << "[WARN] TCP connect failed\n";
213 }
214 s->Close();
215}
216
217TrialResult RunOnce(const std::string& proto, double distanceKm, double TDepMs, bool verbose) {
218 const uint16_t port = 9000;
219
220 // Approximate propagation in fiber: 5 microseconds / km
221 const Time qDelay = MicroSeconds(static_cast<int64_t>(std::llround(5.0 * distanceKm)));
222 const Time cDelay = MicroSeconds(static_cast<int64_t>(std::llround(5.0 * distanceKm)));
223
224 BobInfo bobInfo;
225 Time tStart = Seconds(0);
226
227 NetController net;
228 net.SetQStateBackend(QStateBackend::Ket);
229
230 auto A = net.CreateNode();
231 auto B = net.CreateNode();
232
233 // Reference node for the ideal |+> state
234 auto ref = net.CreateNode();
235 auto qRef = ref->CreateQubit();
236 ref->Apply(gates::H(), {qRef});
237
238 // Bob memory-noise map: p = 1 - exp(-t / Tdep)
239 auto depol = CreateObject<DepolarizingQMap>();
240 if (TDepMs > 0.0) {
241 const double ratePerSecond = 1000.0 / TDepMs; // TDepMs is in ms
242 depol->SetAttribute("Rate", DoubleValue(ratePerSecond));
243 } else {
244 depol->SetAttribute("Probability", DoubleValue(0.0));
245 }
246
247 auto u = CreateObject<UniformRandomVariable>();
248
249 // Quantum link
250 auto ch = net.InstallQuantumLink(A, B);
251 ch->SetAttribute("Delay", TimeValue(qDelay));
252
253 // Classical link
254 InternetStackHelper internet;
255 internet.Install(A);
256 internet.Install(B);
257
258 PointToPointHelper p2p;
259 p2p.SetDeviceAttribute("DataRate", StringValue("100Mbps"));
260 p2p.SetChannelAttribute("Delay", TimeValue(cDelay));
261 NetDeviceContainer devices = p2p.Install(A, B);
262
263 Ipv4AddressHelper ip;
264 ip.SetBase("10.1.1.0", "255.255.255.0");
265 Ipv4InterfaceContainer interfaces = ip.Assign(devices);
266
267 // Receiver side: PacketSink handles the transport-specific listening/accept path.
268 Address bindAddr = InetSocketAddress(Ipv4Address::GetAny(), port);
269 PacketSinkHelper sinkHelper((proto == "udp") ? "ns3::UdpSocketFactory" : "ns3::TcpSocketFactory",
270 bindAddr);
271 ApplicationContainer sinkApps = sinkHelper.Install(B);
272 sinkApps.Start(Seconds(0.0));
273 sinkApps.Stop(Seconds(5.0));
274
275 Ptr<PacketSink> sink = DynamicCast<PacketSink>(sinkApps.Get(0));
276 if (!sink) {
277 NS_ABORT_MSG("Failed to install PacketSink on Bob");
278 }
279
280 // PacketSink trace hookup.
281 // If your local ns-3 build wants RxWithAddresses instead, swap this accordingly.
282 sink->TraceConnectWithoutContext("Rx", MakeBoundCallback(&OnControlRxTrace, B, &bobInfo, &net,
283 depol, u, qRef, &tStart, verbose));
284
285 // Sender side:
286 // UDP = connect/send/close immediately
287 // TCP = connect asynchronously, send pending packet on connect success
288 auto tcpState = std::make_shared<TcpSendState>();
289 tcpState->verbose = verbose;
290
291 // Bob's quantum receive callback
292 B->SetRecvCallback(
293 [B, &bobInfo, &net, depol, u, qRef, &tStart, verbose](std::shared_ptr<Qubit> q) {
294 bobInfo.qRemote = q;
295 bobInfo.qubitArrived = true;
296 bobInfo.tQubitArrive = Simulator::Now();
297
298 if (verbose) {
299 std::cout << "[RECV][quantum][B] t=" << std::fixed << std::setprecision(6)
300 << Simulator::Now().GetSeconds() << " s\n";
301 }
302
303 TryCorrections(B, net, bobInfo, depol, u, qRef, tStart, verbose);
304 });
305
306 auto sendCtrlPacket = [&](Ptr<Packet> pkt) {
307 InetSocketAddress dst(interfaces.GetAddress(1), port);
308
309 if (proto == "udp") {
310 Ptr<Socket> sock = Socket::CreateSocket(A, UdpSocketFactory::GetTypeId());
311 if (sock->Connect(dst) == 0) {
312 sock->Send(pkt);
313 if (verbose) {
314 std::cout << "[SEND][classical][udp] A->B\n";
315 }
316 } else if (verbose) {
317 std::cout << "[WARN] UDP connect failed\n";
318 }
319 sock->Close();
320 return;
321 }
322
323 Ptr<Socket> sock = Socket::CreateSocket(A, TcpSocketFactory::GetTypeId());
324 tcpState->pendingPkt = pkt;
325 tcpState->sent = false;
326
327 sock->SetConnectCallback(MakeBoundCallback(&OnTcpConnectSuccess, tcpState),
328 MakeBoundCallback(&OnTcpConnectFail, verbose));
329
330 int rc = sock->Connect(dst);
331 if (rc != 0) {
332 if (verbose) {
333 std::cout << "[WARN] TCP connect() immediate failure\n";
334 }
335 sock->Close();
336 tcpState->pendingPkt = nullptr;
337 }
338 };
339
340 // Teleportation protocol
341 Simulator::Schedule(NanoSeconds(1), [&]() {
342 tStart = Simulator::Now();
343
344 auto [qA, qBRemote] = A->CreateBellPair();
345 const bool ok = A->Send(qBRemote, B->GetId());
346
347 if (verbose) {
348 std::cout << "[SEND][quantum] A->B: " << (ok ? "ok" : "failed") << "\n";
349 }
350
351 auto psi = A->CreateQubit();
352 A->Apply(gates::H(), {psi});
353
354 auto [m1, m2] = A->MeasureBell(psi, qA);
355
356 if (verbose) {
357 std::cout << "[A] BSM results: " << m1 << ", " << m2 << "\n";
358 }
359
360 uint8_t bytes[2] = {
361 static_cast<uint8_t>(m1),
362 static_cast<uint8_t>(m2),
363 };
364
365 sendCtrlPacket(Create<Packet>(bytes, 2));
366 });
367
368 Simulator::Stop(Seconds(5));
369 Simulator::Run();
370 Simulator::Destroy();
371
372 TrialResult r;
373 r.fidelity = bobInfo.finalFidelity;
374 r.completionMs = bobInfo.completionMs;
375 return r;
376}
377
378} // namespace
379
380int main(int argc, char* argv[]) {
381 std::string proto = "udp";
382 double distanceKm = 50.0;
383 double TDepMs = 5.0;
384 uint32_t trials = 10;
385 uint32_t seed = 1;
386 uint32_t run = 1;
387 bool verbose = false;
388
389 CommandLine cmd;
390 cmd.AddValue("proto", "udp | tcp", proto);
391 cmd.AddValue("distanceKm", "Distance between Alice and Bob in km", distanceKm);
392 cmd.AddValue("TDepMs", "Bob memory characteristic time in ms (0 => ideal memory)", TDepMs);
393 cmd.AddValue("trials", "Number of repeated trials", trials);
394 cmd.AddValue("seed", "ns-3 RNG seed", seed);
395 cmd.AddValue("run", "ns-3 RNG run number", run);
396 cmd.AddValue("verbose", "Print per-trial details", verbose);
397 cmd.Parse(argc, argv);
398
399 if (proto != "udp" && proto != "tcp") {
400 NS_ABORT_MSG("--proto must be udp or tcp");
401 }
402
403 RngSeedManager::SetSeed(seed);
404
405 RunningStats fidelityStats;
406 RunningStats latencyStats;
407
408 if (verbose) {
409 std::cout << "[DEMO] Noisy teleportation experiment starting\n";
410 std::cout << " proto = " << proto << "\n";
411 std::cout << " distanceKm = " << distanceKm << "\n";
412 std::cout << " TDepMs = " << TDepMs << "\n";
413 std::cout << " trials = " << trials << "\n";
414 }
415
416 for (uint32_t t = 0; t < trials; ++t) {
417 RngSeedManager::SetRun(run + t);
418
419 if (verbose) {
420 std::cout << "\n[TRIAL " << (t + 1) << "/" << trials << "]\n";
421 }
422
423 TrialResult r = RunOnce(proto, distanceKm, TDepMs, verbose);
424 fidelityStats.Add(r.fidelity);
425 latencyStats.Add(r.completionMs);
426 }
427
428 std::cout << "\n[RESULT]"
429 << " proto=" << proto << " distance_km=" << std::fixed << std::setprecision(3)
430 << distanceKm << " TDep_ms=" << TDepMs << " trials=" << trials
431 << " fidelity_mean=" << std::setprecision(4) << fidelityStats.Mean()
432 << " fidelity_median=" << fidelityStats.Median()
433 << " fidelity_stddev=" << fidelityStats.StdDev()
434 << " latency_mean_ms=" << std::setprecision(4) << latencyStats.Mean()
435 << " latency_median_ms=" << latencyStats.Median()
436 << " latency_stddev_ms=" << latencyStats.StdDev() << "\n";
437
438 if (verbose) {
439 std::cout << "[DONE] Noisy teleportation experiment finished\n";
440 }
441
442 return 0;
443}
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(const std::string &proto, double distanceKm, double TDepMs, bool verbose)
static void OnTcpConnectSuccess(std::shared_ptr< TcpSendState > tcpState, Ptr< Socket > s)
static void OnControlRxTrace(Ptr< QNode > bob, BobInfo *bobInfo, NetController *net, Ptr< DepolarizingQMap > depol, Ptr< UniformRandomVariable > u, std::shared_ptr< Qubit > qRef, Time *tStart, bool verbose, Ptr< const Packet > packet, const Address &)
void TryCorrections(Ptr< QNode > bob, NetController &net, BobInfo &info, Ptr< DepolarizingQMap > depol, Ptr< UniformRandomVariable > u, std::shared_ptr< Qubit > qRef, 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