61int main(
int argc,
char** argv) {
62 std::cout <<
"[DEMO] Channel-loss entanglement distribution starting\n";
65 double lossProb = 0.8;
67 RngSeedManager::SetSeed(1);
70 cmd.AddValue(
"run",
"RNG run index", run);
71 cmd.AddValue(
"loss-prob",
"Per-qubit loss probability [0,1]", lossProb);
72 cmd.Parse(argc, argv);
74 RngSeedManager::SetRun(run);
77 Trace(
"Entanglement Distribution with Photon Loss (loss-prob=", lossProb,
" run=", run,
")");
79 Time::SetResolution(Time::NS);
92 const Time kSingleGate = NanoSeconds(100);
93 const Time kTwoQGate = NanoSeconds(300);
94 const Time kQDelay = NanoSeconds(10);
95 const Time kClassical = kQDelay;
98 const Time kDstTimeout = NanoSeconds(5);
102 ch->SetAttribute(
"Delay", TimeValue(kQDelay));
104 auto lossMap = CreateObject<LossQMap>();
105 lossMap->SetAttribute(
"Probability", DoubleValue(lossProb));
106 ch->SetQMap(lossMap);
111 InternetStackHelper internet;
112 internet.Install(src);
113 internet.Install(dst);
115 PointToPointHelper p2p;
116 p2p.SetDeviceAttribute(
"DataRate", StringValue(
"100Mbps"));
117 p2p.SetChannelAttribute(
"Delay", StringValue(
"10ns"));
119 Ipv4AddressHelper ipv4;
120 ipv4.SetBase(
"10.1.1.0",
"255.255.255.0");
121 auto ifsSD = ipv4.Assign(p2p.Install(src, dst));
122 Ipv4GlobalRoutingHelper::PopulateRoutingTables();
125 const Ipv4Address kSrcAddr = ifsSD.GetAddress(0);
126 const Ipv4Address kDstAddr = ifsSD.GetAddress(1);
133 auto srcCtrlRx = Socket::CreateSocket(src, UdpSocketFactory::GetTypeId());
134 srcCtrlRx->Bind(InetSocketAddress(Ipv4Address::GetAny(),
kCtrlPort));
135 auto dstCtrlTx = Socket::CreateSocket(dst, UdpSocketFactory::GetTypeId());
136 dstCtrlTx->Connect(InetSocketAddress(kSrcAddr,
kCtrlPort));
139 auto dstNotifyRx = Socket::CreateSocket(dst, UdpSocketFactory::GetTypeId());
140 dstNotifyRx->Bind(InetSocketAddress(Ipv4Address::GetAny(),
kNotifyPort));
141 auto srcNotifyTx = Socket::CreateSocket(src, UdpSocketFactory::GetTypeId());
142 srcNotifyTx->Connect(InetSocketAddress(kDstAddr,
kNotifyPort));
146 int dstLatestArrived = 0;
147 std::shared_ptr<Qubit> currentMemQ;
148 std::string currentMemLabel;
150 std::function<void()> scheduleAttempt;
153 dstNotifyRx->SetRecvCallback([&](Ptr<Socket> sock) {
156 while ((pkt = sock->RecvFrom(from))) {
158 pkt->CopyData(&attByte, 1);
159 const int att = static_cast<int>(attByte);
161 std::cout <<
"[DEST] Notify for attempt " << att <<
" - arming timeout\n";
162 TraceNodeText(
"Destination", StrCat(
"Expecting qubit (attempt ", att,
")"));
164 Simulator::Schedule(kDstTimeout, [&, att]() {
165 if (dstLatestArrived >= att) return;
166 std::cout <<
"[DEST] Attempt " << att <<
" timeout - qubit lost, sending timeout signal\n";
167 TraceNodeText(
"Destination", StrCat(
"Timeout: attempt ", att,
" - qubit lost"));
168 TraceRemoveQubit(
"fly_" + std::to_string(att),
"lost");
169 const auto tNow = Simulator::Now();
170 uint8_t buf[2] = {0x00, static_cast<uint8_t>(att)};
171 dstCtrlTx->Send(Create<Packet>(buf, 2));
172 TraceSendPacket(
"Destination",
"Source", tNow, tNow + kClassical,
173 StrCat(
"timeout: attempt ", att),
"udp");
179 dst->SetRecvCallback([&](std::shared_ptr<Qubit> q) {
180 dstLatestArrived = attemptNum;
182 Trace(
"Destination received ", q->GetLabel());
183 std::cout <<
"[DEST] " << q->GetLabel() <<
" arrived\n";
184 const auto tNow = Simulator::Now();
185 uint8_t buf[2] = {0x01,
static_cast<uint8_t
>(attemptNum)};
186 dstCtrlTx->Send(Create<Packet>(buf, 2));
188 StrCat(
"ACK: ", q->GetLabel()),
"udp");
192 srcCtrlRx->SetRecvCallback([&](Ptr<Socket> sock) {
195 while ((pkt = sock->RecvFrom(from))) {
196 uint8_t buf[2] = {0, 0};
197 pkt->CopyData(buf, 2);
198 const bool isAck = (buf[0] == 0x01);
199 const int att =
static_cast<int>(buf[1]);
201 Trace(
"Source received ACK - entanglement established on attempt ", attemptNum);
202 TraceNodeText(
"Source",
"ACK received - entanglement distributed!");
203 std::cout <<
"[SOURCE] ACK on attempt " << attemptNum <<
" - success\n";
206 std::cout <<
"[SOURCE] Timeout for attempt " << att <<
" - retrying\n";
207 Trace(
"Timeout for attempt ", att,
" - qubit lost");
211 Simulator::Schedule(NanoSeconds(100), scheduleAttempt);
217 scheduleAttempt = [&]() {
221 std::cout <<
"[SOURCE] Max attempts (" <<
kMaxAttempts <<
") reached - giving up\n";
227 const std::string memLabel =
"mem_" + std::to_string(attemptNum);
228 const std::string flyLabel =
"fly_" + std::to_string(attemptNum);
230 Trace(
"Attempt ", attemptNum,
": Source generates Bell pair (", memLabel,
", ", flyLabel,
")");
233 auto memQ = src->CreateQubit(memLabel);
234 auto flyQ = src->CreateQubit(flyLabel);
236 currentMemLabel = memLabel;
241 const int thisAttempt = attemptNum;
242 const uint8_t attByte =
static_cast<uint8_t
>(thisAttempt);
245 Simulator::Schedule(kSingleGate, [=, &srcNotifyTx]() {
250 Simulator::Schedule(kTwoQGate, [=, &srcNotifyTx]() {
259 Simulator::Schedule(kSingleGate, [=, &srcNotifyTx]() {
260 const auto tSend = Simulator::Now();
262 src->Send(flyQ, dst->GetId());
263 TraceSendQubit(flyLabel,
"Source",
"Destination", tSend, tSend + kQDelay);
266 srcNotifyTx->Send(Create<Packet>(&attByte, 1));
268 StrCat(
"notify: attempt ", thisAttempt),
"udp");
271 std::cout <<
"[SOURCE] Attempt " << thisAttempt <<
": " << flyLabel <<
" sent\n";
278 Simulator::Schedule(MicroSeconds(1), scheduleAttempt);
280 Simulator::Stop(MilliSeconds(1));
282 Simulator::Destroy();
285 std::cout <<
"[DONE] Channel-loss example finished\n";