• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sfc-aqua / quisp / 4329255112

pending completion
4329255112

Pull #504

github

GitHub
Merge 948c96a03 into 3166d7e57
Pull Request #504: Integrate Message Exchange (Purification/Entanglement Swapping) into RuleSet and Runtime

957 of 957 new or added lines in 22 files covered. (100.0%)

2287 of 5806 relevant lines covered (39.39%)

46937.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

4.14
/quisp/modules/QRSA/HardwareMonitor/HardwareMonitor.cc
1
/** \file HardwareMonitor.cc
2
 *
3
 *  \brief HardwareMonitor
4
 */
5
#include "HardwareMonitor.h"
6

7
#include <fstream>
8
#include <iostream>
9
#include <memory>
10
#include <sstream>
11
#include <string>
12

13
#include <omnetpp/cexception.h>
14
#include <unsupported/Eigen/KroneckerProduct>
15
#include <unsupported/Eigen/MatrixFunctions>
16

17
#include "messages/classical_messages.h"
18
#include "modules/PhysicalConnection/BSA/BSAController.h"
19
#include "modules/PhysicalConnection/BSA/BellStateAnalyzer.h"
20
#include "rules/RuleSet.h"
21

22
using namespace quisp::messages;
23
using namespace quisp::rules;
24
using Eigen::Matrix4cd;
25
using Eigen::Vector4cd;
26

27
namespace quisp::modules {
28

29
HardwareMonitor::HardwareMonitor() : provider(utils::ComponentProvider{this}) {}
1✔
30
HardwareMonitor::~HardwareMonitor() {}
1✔
31

32
// HardwareMonitor is also responsible for calculating the rssi/oka's protocol/fidelity calculate and give it to the RoutingDaemon
33
void HardwareMonitor::initialize(int stage) {
1✔
34
  EV_INFO << "HardwareMonitor booted\n";
1✔
35
  routing_daemon = provider.getRoutingDaemon();
1✔
36

37
  output_count initial;
1✔
38
  initial.minus_minus = 0;
1✔
39
  initial.minus_plus = 0;
1✔
40
  initial.plus_minus = 0;
1✔
41
  initial.plus_plus = 0;
1✔
42
  initial.total_count = 0;
1✔
43

44
  Pauli.X << 0, 1, 1, 0;
1✔
45
  Pauli.Y << 0, std::complex<double>(0, -1), std::complex<double>(0, 1), 0;
1✔
46
  Pauli.Z << 1, 0, 0, -1;
1✔
47
  Pauli.I << 1, 0, 0, 1;
1✔
48

49
  num_qnic_rp = par("number_of_qnics_rp");
1✔
50
  num_qnic_r = par("number_of_qnics_r");
1✔
51
  num_qnic = par("number_of_qnics");
1✔
52
  num_qnic_total = num_qnic + num_qnic_r + num_qnic_rp;
1✔
53

54
  num_end_nodes = routing_daemon->getNumEndNodes();
1✔
55

56
  /* This is used to keep your own tomography data, and also to match and store the received partner's tomography data */
57
  // Assumes link tomography only between neighbors.
58
  temporal_tomography_output = new TomographyOutcomeTable[num_qnic_total];
1✔
59
  tomography_runningtime_holder = new LinkCostMap[num_qnic_total];
1✔
60

61
  /*This keeps which node is connected to which local qnic.*/
62
  tomography_output_filename = par("tomography_output_filename").str();
1✔
63
  // remove double quotes at the beginning and end
64
  tomography_output_filename = tomography_output_filename.substr(1, tomography_output_filename.length() - 2);
1✔
65
  file_dir_name = par("file_dir_name").str();
1✔
66
  do_link_level_tomography = par("link_tomography");
1✔
67
  num_purification = par("initial_purification");
1✔
68
  X_Purification = par("x_purification");
1✔
69
  Z_Purification = par("z_purification");
1✔
70
  purification_type = par("purification_type");
1✔
71
  num_measure = par("num_measure");
1✔
72
  my_address = par("address");
1✔
73

74
  if (stage == 0) {
1✔
75
    return;
1✔
76
  }
1✔
77

78
  prepareNeighborTable();
×
79
  WATCH_MAP(neighbor_table);
×
80

81
  if (do_link_level_tomography) {
×
82
    for (auto it = neighbor_table.cbegin(); it != neighbor_table.cend(); ++it) {
×
83
      // You don't want 2 separate tomography processes to run for each link.
84
      // Not a very good solution, but makes sure that only 1 request per link is generated.
85
      if (my_address > it->second.neighborQNode_address) {
×
86
        EV << "Generating tomography rules... for node " << it->second.neighborQNode_address << "\n";
×
87
        LinkTomographyRequest *pk = new LinkTomographyRequest("LinkTomographyRequest");
×
88
        pk->setDestAddr(it->second.neighborQNode_address);
×
89
        pk->setSrcAddr(my_address);
×
90
        pk->setKind(6);
×
91
        send(pk, "RouterPort$o");
×
92
      }
×
93
    }
×
94
  }
×
95
}
×
96

97
unsigned long HardwareMonitor::createUniqueId() {
×
98
  auto time = SimTime().str();
×
99
  auto address = std::to_string(my_address);
×
100
  auto random = std::to_string(intuniform(0, 10000000));
×
101
  auto hash_seed = address + time + random;
×
102
  std::hash<std::string> hash_fn;
×
103
  size_t t = hash_fn(hash_seed);
×
104
  unsigned long ruleset_id = static_cast<long>(t);
×
105
  std::cout << "Hash is " << hash_seed << ", t = " << t << ", long = " << ruleset_id << "\n";
×
106
  return ruleset_id;
×
107
}
×
108

109
std::unique_ptr<InterfaceInfo> HardwareMonitor::findInterfaceByNeighborAddr(int neighbor_address) {
×
110
  for (auto it = neighbor_table.cbegin(); it != neighbor_table.cend(); ++it) {
×
111
    if (it->second.neighborQNode_address == neighbor_address) {
×
112
      // return unique_ptr<InterfaceInfo>(new InterfaceInfo(it->second));
113
      return std::make_unique<InterfaceInfo>(it->second);
×
114
    }
×
115
  }
×
116
  return nullptr;
×
117
}
×
118

119
void HardwareMonitor::handleMessage(cMessage *msg) {
×
120
  if (auto *request = dynamic_cast<LinkTomographyRequest *>(msg)) {
×
121
    /* Received a tomography request from neighbor */
122

123
    auto info = findInterfaceByNeighborAddr(request->getSrcAddr());
×
124
    if (info == nullptr) {
×
125
      error("1. Something is wrong when finding out local qnic address from neighbor address in neighbor_table.");
×
126
    }
×
127

128
    /*Prepare an acknowledgment*/
129
    LinkTomographyAck *pk = new LinkTomographyAck("LinkTomographyAck");
×
130
    pk->setSrcAddr(my_address);
×
131
    pk->setDestAddr(request->getSrcAddr());
×
132
    pk->setKind(6);
×
133
    pk->setQnic_index(info->qnic.index);
×
134
    pk->setQnic_type(info->qnic.type);
×
135

136
    send(pk, "RouterPort$o");
×
137
    delete request;
×
138
    return;
×
139
  }
×
140

141
  if (auto *ack = dynamic_cast<LinkTomographyAck *>(msg)) {
×
142
    /*Received an acknowledgment for tomography from neighbor.*/
143

144
    /*Create and send RuleSets*/
145
    int partner_address = ack->getSrcAddr();
×
146

147
    auto my_qnic_info = findInterfaceByNeighborAddr(partner_address);
×
148
    if (my_qnic_info == nullptr) {
×
149
      error("2. Something is wrong when finding out local qnic address from neighbor address in neighbor_table.");
×
150
    }
×
151

152
    // RuleSets sent for this node and the partner node.
153
    long RuleSet_id = createUniqueId();
×
154
    sendLinkTomographyRuleSet(my_address, partner_address, my_qnic_info->qnic.type, my_qnic_info->qnic.index, RuleSet_id);
×
155

156
    QNIC_type partner_qnic_type = ack->getQnic_type();
×
157
    int partner_qnic_index = ack->getQnic_index();
×
158
    sendLinkTomographyRuleSet(partner_address, my_address, partner_qnic_type, partner_qnic_index, RuleSet_id);
×
159
    delete ack;
×
160
    return;
×
161
  }
×
162

163
  if (auto *result = dynamic_cast<LinkTomographyResult *>(msg)) {
×
164
    /*Link tomography measurement result/basis from neighbor received.*/
165
    int partner_addr = result->getPartner_address();
×
166
    // Get QNIC info from neighbor address.
167
    int qnic_addr_to_partner = routing_daemon->findQNicAddrByDestAddr(partner_addr);
×
168
    auto local_qnic_info = findConnectionInfoByQnicAddr(qnic_addr_to_partner);
×
169
    if (local_qnic_info == nullptr) {
×
170
      error("local qnic info should not be null");
×
171
    }
×
172
    InterfaceInfo inter_info = getQnicInterfaceByQnicAddr(local_qnic_info->qnic.index, local_qnic_info->qnic.type);
×
173
    QNIC local_qnic = inter_info.qnic;
×
174

175
    // 1. find partner
176
    auto partner_outputs_iter = temporal_tomography_output[local_qnic.address].find(partner_addr);
×
177
    if (partner_outputs_iter != temporal_tomography_output[local_qnic.address].end()) {
×
178
      // partner info found in this output
179
      auto partner_output_iter = temporal_tomography_output[local_qnic.address][partner_addr].find(result->getCount_id());
×
180
      if (partner_output_iter != temporal_tomography_output[local_qnic.address][partner_addr].end()) {
×
181
        EV << "Tomography data already found. Updating with result from partner\n";
×
182
        tomography_outcome temp = partner_output_iter->second;
×
183
        if (result->getSrcAddr() == my_address) {
×
184
          temp.my_basis = result->getBasis();
×
185
          temp.my_output_is_plus = result->getOutput_is_plus();
×
186
          temp.my_GOD_clean = result->getGOD_clean();
×
187
        } else {
×
188
          temp.partner_basis = result->getBasis();
×
189
          temp.partner_output_is_plus = result->getOutput_is_plus();
×
190
          temp.partner_GOD_clean = result->getGOD_clean();
×
191
        }
×
192
        partner_output_iter->second = temp;
×
193
      } else {
×
194
        EV << "Fresh tomography data with partner :" << partner_addr << "\n";
×
195
        tomography_outcome temp;
×
196
        if (result->getSrcAddr() == my_address) {
×
197
          temp.my_basis = result->getBasis();
×
198
          temp.my_output_is_plus = result->getOutput_is_plus();
×
199
          temp.my_GOD_clean = result->getGOD_clean();
×
200
        } else {
×
201
          temp.partner_basis = result->getBasis();
×
202
          temp.partner_output_is_plus = result->getOutput_is_plus();
×
203
          temp.partner_GOD_clean = result->getGOD_clean();
×
204
        }
×
205
        temporal_tomography_output[local_qnic.address][partner_addr].insert(std::make_pair(result->getCount_id(), temp));
×
206
      }
×
207
    } else {
×
208
      // no partner info found in this output
209
      EV << "No partner information found with partner: " << partner_addr << "\n";
×
210
      tomography_outcome temp;
×
211
      if (result->getSrcAddr() == my_address) {
×
212
        temp.my_basis = result->getBasis();
×
213
        temp.my_output_is_plus = result->getOutput_is_plus();
×
214
        temp.my_GOD_clean = result->getGOD_clean();
×
215
      } else {
×
216
        temp.partner_basis = result->getBasis();
×
217
        temp.partner_output_is_plus = result->getOutput_is_plus();
×
218
        temp.partner_GOD_clean = result->getGOD_clean();
×
219
      }
×
220
      // If this partner is new, then initialize tables
221
      std::map<int, tomography_outcome> temp_result;
×
222
      temp_result.insert(std::make_pair(result->getCount_id(), temp));
×
223
      /* temporal_tomography_output is filled in, those data are summarized into basis based measurement outcome table.
224
       * This accumulates the number of ++, +-, -+ and -- for each basis combination.*/
225
      temporal_tomography_output[local_qnic.address].insert(std::make_pair(partner_addr, temp_result));
×
226
      // NOTE: if you do buffer based multiplex and tomogrpahy need hack here
227
      qnic_partner_map.insert(std::make_pair(local_qnic.address, partner_addr));
×
228

229
      // initialize link cost
230
      link_cost temp_cost;
×
231
      temp_cost.Bellpair_per_sec = -1;
×
232
      temp_cost.tomography_measurements = -1;
×
233
      temp_cost.tomography_time = -1;
×
234
      tomography_runningtime_holder[local_qnic.address].insert(std::make_pair(partner_addr, temp_cost));
×
235
    }
×
236

237
    if (result->getFinish() != -1) {
×
238
      EV << "finish? " << result->getFinish() << "\n";
×
239
      EV << "tomography_time: " << tomography_runningtime_holder[local_qnic.address][partner_addr].tomography_time << std::endl;
×
240
      // Pick the slower tomography time MIN(self,partner).
241
      if (tomography_runningtime_holder[local_qnic.address][partner_addr].tomography_time < result->getFinish()) {
×
242
        tomography_runningtime_holder[local_qnic.address][partner_addr].Bellpair_per_sec = (double)result->getMax_count() / result->getFinish().dbl();
×
243
        tomography_runningtime_holder[local_qnic.address][partner_addr].tomography_measurements = result->getMax_count();
×
244
        tomography_runningtime_holder[local_qnic.address][partner_addr].tomography_time = result->getFinish();
×
245

246
        StopEmitting *pk = new StopEmitting("StopEmitting");
×
247
        pk->setQnic_address(local_qnic.address);
×
248
        pk->setDestAddr(my_address);
×
249
        pk->setSrcAddr(my_address);
×
250
        send(pk, "RouterPort$o");
×
251
      }
×
252
    }
×
253
    delete result;
×
254
    return;
×
255
  }
×
256
}
×
257

258
void HardwareMonitor::finish() {
×
259
  EV << "Finishing Hardware Monitor\n";
×
260
  // file name
261
  std::string file_name = tomography_output_filename;
×
262
  std::string df = "default";
×
263
  if (file_name.compare(df) == 0) {
×
264
    std::cout << df << "==" << file_name << "\n";
×
265
    file_name = std::string("Tomography_") + std::string(getSimulation()->getNetworkType()->getFullName());
×
266
  } else {
×
267
    std::cout << df << "!=" << file_name << "\n";
×
268
  }
×
269
  std::string file_name_dm = file_name + std::string("_dm");
×
270
  std::ofstream tomography_stats(file_name, std::ios_base::app);
×
271
  std::ofstream tomography_dm(file_name_dm, std::ios_base::app);
×
272
  std::cout << "Opened new file to write.\n";
×
273

274
  // here generate tomography data storage
275
  tomography_data = new raw_data[num_qnic_total];
×
276

277
  output_count initial;
×
278
  initial.minus_minus = 0;
×
279
  initial.minus_plus = 0;
×
280
  initial.plus_minus = 0;
×
281
  initial.plus_plus = 0;
×
282
  initial.total_count = 0;
×
283
  for (auto it = qnic_partner_map.begin(); it != qnic_partner_map.end(); ++it) {
×
284
    int qnic_id = it->first;
×
285
    int part = it->second;
×
286
    tomography_data[qnic_id][part].insert(std::make_pair("XX", initial));
×
287
    tomography_data[qnic_id][part].insert(std::make_pair("XY", initial));
×
288
    tomography_data[qnic_id][part].insert(std::make_pair("XZ", initial));
×
289
    tomography_data[qnic_id][part].insert(std::make_pair("ZX", initial));
×
290
    tomography_data[qnic_id][part].insert(std::make_pair("ZY", initial));
×
291
    tomography_data[qnic_id][part].insert(std::make_pair("ZZ", initial));
×
292
    tomography_data[qnic_id][part].insert(std::make_pair("YX", initial));
×
293
    tomography_data[qnic_id][part].insert(std::make_pair("YY", initial));
×
294
    tomography_data[qnic_id][part].insert(std::make_pair("YZ", initial));
×
295
  }
×
296

297
  for (auto it = qnic_partner_map.begin(); it != qnic_partner_map.end(); it++) {
×
298
    int qnic = it->first;
×
299
    int partner_address = it->second;
×
300
    // qnic index
301
    //  - partner address
302
    //  - - measurement counts
303
    // qnic index
304
    // initial variables for this tomography partner
305
    int meas_total = 0;  // total number of measurement
×
306
    int GOD_clean_pair_total = 0;  // clean pair?
×
307
    int GOD_X_pair_total = 0;
×
308
    int GOD_Z_pair_total = 0;
×
309
    int GOD_Y_pair_total = 0;
×
310

311
    for (auto it = temporal_tomography_output[qnic][partner_address].begin(); it != temporal_tomography_output[qnic][partner_address].end(); it++) {
×
312
      std::string basis_combination = "";
×
313
      basis_combination += it->second.my_basis;
×
314
      basis_combination += it->second.partner_basis;
×
315
      if (tomography_data[qnic][partner_address].count(basis_combination) != 1) {
×
316
        error("Basis combination for tomography with partner: %d at %d is not found", partner_address, qnic);
×
317
      }
×
318
      tomography_data[qnic][partner_address][basis_combination].total_count++;
×
319
      // the number of total measurement
320
      meas_total++;
×
321

322
      EV_DEBUG << it->second.my_GOD_clean << "," << it->second.partner_GOD_clean << "\n";
×
323
      // count for ideal state?
324
      // clean pair ... no error bell pairs
325
      // X pair ... X error bell pairs?
326
      // Y pair ... Y error bell pairs?
327
      // Z pair ... Z error bell pairs?
328
      if ((it->second.my_GOD_clean == 'F' && it->second.partner_GOD_clean == 'F') || (it->second.my_GOD_clean == 'X' && it->second.partner_GOD_clean == 'X') ||
×
329
          (it->second.my_GOD_clean == 'Z' && it->second.partner_GOD_clean == 'Z') || (it->second.my_GOD_clean == 'Y' && it->second.partner_GOD_clean == 'Y')) {
×
330
        GOD_clean_pair_total++;
×
331
      } else if ((it->second.my_GOD_clean == 'X' && it->second.partner_GOD_clean == 'F') || (it->second.my_GOD_clean == 'F' && it->second.partner_GOD_clean == 'X')) {
×
332
        GOD_X_pair_total++;
×
333
      } else if ((it->second.my_GOD_clean == 'Z' && it->second.partner_GOD_clean == 'F') || (it->second.my_GOD_clean == 'F' && it->second.partner_GOD_clean == 'Z')) {
×
334
        GOD_Z_pair_total++;
×
335
      } else if ((it->second.my_GOD_clean == 'Y' && it->second.partner_GOD_clean == 'F') || (it->second.my_GOD_clean == 'F' && it->second.partner_GOD_clean == 'Y')) {
×
336
        GOD_Y_pair_total++;
×
337
      }
×
338

339
      // empirical result
340
      if (it->second.my_output_is_plus && it->second.partner_output_is_plus) {
×
341
        // mine: +, partner: +
342
        tomography_data[qnic][partner_address][basis_combination].plus_plus++;
×
343
      } else if (it->second.my_output_is_plus && !it->second.partner_output_is_plus) {
×
344
        // mine: +, partner: -
345
        tomography_data[qnic][partner_address][basis_combination].plus_minus++;
×
346
      } else if (!it->second.my_output_is_plus && it->second.partner_output_is_plus) {
×
347
        // mine: -, partner: +
348
        tomography_data[qnic][partner_address][basis_combination].minus_plus++;
×
349
      } else if (!it->second.my_output_is_plus && !it->second.partner_output_is_plus) {
×
350
        // mine: -, partner: -
351
        tomography_data[qnic][partner_address][basis_combination].minus_minus++;
×
352
      } else {
×
353
        error("This should not happen though..... ?");
×
354
      }
×
355
    }  // end for
×
356
    Matrix4cd extended_density_matrix_reconstructed = reconstruct_density_matrix(qnic, partner_address);
×
357

358
    Vector4cd Bellpair;
×
359
    Bellpair << 1 / sqrt(2), 0, 0, 1 / sqrt(2);
×
360
    Matrix4cd density_matrix_ideal = Bellpair * Bellpair.adjoint();
×
361
    double fidelity = (extended_density_matrix_reconstructed.real() * density_matrix_ideal.real()).trace();
×
362

363
    Vector4cd Bellpair_X;
×
364
    Bellpair_X << 0, 1 / sqrt(2), 1 / sqrt(2), 0;
×
365
    Matrix4cd density_matrix_X = Bellpair_X * Bellpair_X.adjoint();
×
366
    double Xerr_rate = (extended_density_matrix_reconstructed.real() * density_matrix_X.real()).trace();
×
367
    EV << "Xerr = " << Xerr_rate << "\n";
×
368

369
    Vector4cd Bellpair_Z;
×
370
    Bellpair_Z << 1 / sqrt(2), 0, 0, -1 / sqrt(2);
×
371
    Matrix4cd density_matrix_Z = Bellpair_Z * Bellpair_Z.adjoint();
×
372
    double Zerr_rate = (extended_density_matrix_reconstructed.real() * density_matrix_Z.real()).trace();
×
373
    std::complex<double> checkZ = Bellpair_Z.adjoint() * extended_density_matrix_reconstructed * Bellpair_Z;
×
374
    EV << "Zerr = " << Zerr_rate << " or, " << checkZ.real() << "+" << checkZ.imag() << "\n";
×
375

376
    Vector4cd Bellpair_Y;
×
377
    Bellpair_Y << 0, std::complex<double>(0, 1 / sqrt(2)), std::complex<double>(0, -1 / sqrt(2)), 0;
×
378
    Matrix4cd density_matrix_Y = Bellpair_Y * Bellpair_Y.adjoint();
×
379
    double Yerr_rate = (extended_density_matrix_reconstructed.real() * density_matrix_Y.real()).trace();
×
380
    EV << "Yerr = " << Yerr_rate << "\n";
×
381

382
    // FIXME should be updated
383
    double denom = fidelity * fidelity * tomography_runningtime_holder[qnic][partner_address].Bellpair_per_sec;
×
384
    double link_cost;
×
385
    // TODO currently, it's just placed. consider how to culculate this
386
    if (denom != 0) {
×
387
      link_cost = (double)1 / denom;
×
388
    } else {
×
389
      link_cost = 1;
×
390
    }
×
391
    auto info = findConnectionInfoByQnicAddr(qnic);
×
392
    if (info == nullptr) {
×
393
      error("info not found");
×
394
    }
×
395
    // outputs
396
    InterfaceInfo interface = getQnicInterfaceByQnicAddr(info->qnic.index, info->qnic.type);
×
397
    cModule *this_node = this->getParentModule()->getParentModule();
×
398
    cModule *partner_node = getQNodeWithAddress(partner_address);
×
399
    cChannel *channel = interface.qnic.pointer->gate("qnic_quantum_port$o")->getNextGate()->getChannel();
×
400
    double dis = channel->par("distance");
×
401
    if (partner_node == nullptr) {
×
402
      error("here, partner node is null");
×
403
    }
×
404
    // density matrix output
405
    tomography_dm << this_node->getFullName() << "<--->" << partner_node->getFullName() << "\n";
×
406
    tomography_dm << "REAL\n";
×
407
    tomography_dm << extended_density_matrix_reconstructed.real() << "\n";
×
408
    tomography_dm << "IMAGINARY\n";
×
409
    tomography_dm << extended_density_matrix_reconstructed.imag() << "\n";
×
410

411
    // link stats output
412
    tomography_stats << this_node->getFullName() << "<-->QuantumChannel{cost=" << link_cost << ";distance=" << dis << "km;fidelity=" << fidelity
×
413
                     << ";bellpair_per_sec=" << tomography_runningtime_holder[qnic][partner_address].Bellpair_per_sec
×
414
                     << ";tomography_time=" << tomography_runningtime_holder[qnic][partner_address].tomography_time
×
415
                     << ";tomography_measurements=" << tomography_runningtime_holder[qnic][partner_address].tomography_measurements << ";actual_meas=" << meas_total
×
416
                     << "; GOD_clean_pair_total=" << GOD_clean_pair_total << "; GOD_X_pair_total=" << GOD_X_pair_total << "; GOD_Y_pair_total=" << GOD_Y_pair_total
×
417
                     << "; GOD_Z_pair_total=" << GOD_Z_pair_total << ";}<-->" << partner_node->getFullName() << "; F=" << fidelity << "; X=" << Xerr_rate << "; Z=" << Zerr_rate
×
418
                     << "; Y=" << Yerr_rate << endl;
×
419
    // this is a temporary implementation so that the e2e-test can read fidelity and error rates
420
    std::cout << this_node->getFullName() << "<-->QuantumChannel{cost=" << link_cost << ";distance=" << dis << "km;fidelity=" << fidelity
×
421
              << ";bellpair_per_sec=" << tomography_runningtime_holder[qnic][partner_address].Bellpair_per_sec << ";}<-->" << partner_node->getFullName()
×
422
              << "; Fidelity=" << fidelity << "; Xerror=" << Xerr_rate << "; Zerror=" << Zerr_rate << "; Yerror=" << Yerr_rate << endl;
×
423
  }
×
424
  tomography_stats.close();
×
425
  tomography_dm.close();
×
426
  std::cout << "Closed file to write.\n";
×
427
}
×
428

429
Matrix4cd HardwareMonitor::reconstruct_density_matrix(int qnic_id, int partner) {
×
430
  // II
431
  auto data = tomography_data[qnic_id][partner];
×
432
  double S00 = 1.0;
×
433
  double S01 = (double)data["XX"].plus_plus / (double)data["XX"].total_count - (double)data["XX"].plus_minus / (double)data["XX"].total_count +
×
434
               (double)data["XX"].minus_plus / (double)data["XX"].total_count - (double)data["XX"].minus_minus / (double)data["XX"].total_count;
×
435
  if (std::isnan(S01)) {
×
436
    EV << "total count: " << (double)data["XX"].total_count << "\n";
×
437
    error("S01 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
438
  }
×
439
  double S02 = (double)data["YY"].plus_plus / (double)data["YY"].total_count - (double)data["YY"].plus_minus / (double)data["YY"].total_count +
×
440
               (double)data["YY"].minus_plus / (double)data["YY"].total_count - (double)data["YY"].minus_minus / (double)data["YY"].total_count;
×
441
  if (std::isnan(S02)) {
×
442
    error("S02 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
443
  }
×
444
  double S03 = (double)data["ZZ"].plus_plus / (double)data["ZZ"].total_count - (double)data["ZZ"].plus_minus / (double)data["ZZ"].total_count +
×
445
               (double)data["ZZ"].minus_plus / (double)data["ZZ"].total_count - (double)data["ZZ"].minus_minus / (double)data["ZZ"].total_count;
×
446
  if (std::isnan(S03)) {
×
447
    error("S03 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
448
  }
×
449
  // XX
450
  double S10 = (double)data["XX"].plus_plus / (double)data["XX"].total_count + (double)data["XX"].plus_minus / (double)data["XX"].total_count -
×
451
               (double)data["XX"].minus_plus / (double)data["XX"].total_count - (double)data["XX"].minus_minus / (double)data["XX"].total_count;
×
452
  if (std::isnan(S10)) {
×
453
    error("S10 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
454
  }
×
455
  double S11 = (double)data["XX"].plus_plus / (double)data["XX"].total_count - (double)data["XX"].plus_minus / (double)data["XX"].total_count -
×
456
               (double)data["XX"].minus_plus / (double)data["XX"].total_count + (double)data["XX"].minus_minus / (double)data["XX"].total_count;
×
457
  if (std::isnan(S11)) {
×
458
    error("S11 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
459
  }
×
460
  double S12 = (double)data["XY"].plus_plus / (double)data["XY"].total_count - (double)data["XY"].plus_minus / (double)data["XY"].total_count -
×
461
               (double)data["XY"].minus_plus / (double)data["XY"].total_count + (double)data["XY"].minus_minus / (double)data["XY"].total_count;
×
462
  if (std::isnan(S12)) {
×
463
    error("S12 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
464
  }
×
465
  double S13 = (double)data["XZ"].plus_plus / (double)data["XZ"].total_count - (double)data["XZ"].plus_minus / (double)data["XZ"].total_count -
×
466
               (double)data["XZ"].minus_plus / (double)data["XZ"].total_count + (double)data["XZ"].minus_minus / (double)data["XZ"].total_count;
×
467
  if (std::isnan(S13)) {
×
468
    error("S13 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
469
  }
×
470
  // YY
471
  double S20 = (double)data["YY"].plus_plus / (double)data["YY"].total_count + (double)data["YY"].plus_minus / (double)data["YY"].total_count -
×
472
               (double)data["YY"].minus_plus / (double)data["YY"].total_count - (double)data["YY"].minus_minus / (double)data["YY"].total_count;
×
473
  if (std::isnan(S20)) {
×
474
    error("S20 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
475
  }
×
476
  double S21 = (double)data["YX"].plus_plus / (double)data["YX"].total_count - (double)data["YX"].plus_minus / (double)data["YX"].total_count -
×
477
               (double)data["YX"].minus_plus / (double)data["YX"].total_count + (double)data["YX"].minus_minus / (double)data["YX"].total_count;
×
478
  if (std::isnan(S21)) {
×
479
    error("S21 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
480
  }
×
481
  double S22 = (double)data["YY"].plus_plus / (double)data["YY"].total_count - (double)data["YY"].plus_minus / (double)data["YY"].total_count -
×
482
               (double)data["YY"].minus_plus / (double)data["YY"].total_count + (double)data["YY"].minus_minus / (double)data["YY"].total_count;
×
483
  if (std::isnan(S22)) {
×
484
    error("S22 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
485
  }
×
486
  double S23 = (double)data["YZ"].plus_plus / (double)data["YZ"].total_count - (double)data["YZ"].plus_minus / (double)data["YZ"].total_count -
×
487
               (double)data["YZ"].minus_plus / (double)data["YZ"].total_count + (double)data["YZ"].minus_minus / (double)data["YZ"].total_count;
×
488
  if (std::isnan(S23)) {
×
489
    error("S23 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
490
  }
×
491
  // ZZ
492
  double S30 = (double)data["ZZ"].plus_plus / (double)data["ZZ"].total_count + (double)data["ZZ"].plus_minus / (double)data["ZZ"].total_count -
×
493
               (double)data["ZZ"].minus_plus / (double)data["ZZ"].total_count - (double)data["ZZ"].minus_minus / (double)data["ZZ"].total_count;
×
494
  if (std::isnan(S30)) {
×
495
    error("S30 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
496
  }
×
497
  double S31 = (double)data["ZX"].plus_plus / (double)data["ZX"].total_count - (double)data["ZX"].plus_minus / (double)data["ZX"].total_count -
×
498
               (double)data["ZX"].minus_plus / (double)data["ZX"].total_count + (double)data["ZX"].minus_minus / (double)data["ZX"].total_count;
×
499
  if (std::isnan(S31)) {
×
500
    error("S31 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
501
  }
×
502
  double S32 = (double)data["ZY"].plus_plus / (double)data["ZY"].total_count - (double)data["ZY"].plus_minus / (double)data["ZY"].total_count -
×
503
               (double)data["ZY"].minus_plus / (double)data["ZY"].total_count + (double)data["ZY"].minus_minus / (double)data["ZY"].total_count;
×
504
  if (std::isnan(S32)) {
×
505
    error("S32 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
506
  }
×
507
  double S33 = (double)data["ZZ"].plus_plus / (double)data["ZZ"].total_count - (double)data["ZZ"].plus_minus / (double)data["ZZ"].total_count -
×
508
               (double)data["ZZ"].minus_plus / (double)data["ZZ"].total_count + (double)data["ZZ"].minus_minus / (double)data["ZZ"].total_count;
×
509
  if (std::isnan(S33)) {
×
510
    error("S33 error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
511
  }
×
512

513
  double S = (double)data["XX"].plus_plus / (double)data["XX"].total_count + (double)data["XX"].plus_minus / (double)data["XX"].total_count +
×
514
             (double)data["XX"].minus_plus / (double)data["XX"].total_count + (double)data["XX"].minus_minus / (double)data["XX"].total_count;
×
515
  if (std::isnan(S)) {
×
516
    error(" final S error at node %d qnic: %d, with partner: %d", my_address, qnic_id, partner);
×
517
  }
×
518

519
  EV << S00 << ", " << S01 << ", " << S02 << ", " << S03 << "\n";
×
520
  EV << S10 << ", " << S11 << ", " << S12 << ", " << S13 << "\n";
×
521
  EV << S20 << ", " << S21 << ", " << S22 << ", " << S23 << "\n";
×
522
  EV << S30 << ", " << S31 << ", " << S32 << ", " << S33 << "\n";
×
523

524
  Matrix4cd extended_density_matrix_reconstructed =
×
525
      (double)1 / (double)4 *
×
526
      (S01 * kroneckerProduct(Pauli.I, Pauli.X).eval() + S02 * kroneckerProduct(Pauli.I, Pauli.Y).eval() + S03 * kroneckerProduct(Pauli.I, Pauli.Z).eval() +
×
527
       S10 * kroneckerProduct(Pauli.X, Pauli.I).eval() + S11 * kroneckerProduct(Pauli.X, Pauli.X).eval() + S12 * kroneckerProduct(Pauli.X, Pauli.Y).eval() +
×
528
       S13 * kroneckerProduct(Pauli.X, Pauli.Z).eval() + S20 * kroneckerProduct(Pauli.Y, Pauli.I).eval() + S21 * kroneckerProduct(Pauli.Y, Pauli.X).eval() +
×
529
       S22 * kroneckerProduct(Pauli.Y, Pauli.Y).eval() + S23 * kroneckerProduct(Pauli.Y, Pauli.Z).eval() + S30 * kroneckerProduct(Pauli.Z, Pauli.I).eval() +
×
530
       S31 * kroneckerProduct(Pauli.Z, Pauli.X).eval() + S32 * kroneckerProduct(Pauli.Z, Pauli.Y).eval() + S33 * kroneckerProduct(Pauli.Z, Pauli.Z).eval() +
×
531
       S * kroneckerProduct(Pauli.I, Pauli.I).eval());
×
532
  EV << "DM = " << extended_density_matrix_reconstructed << "\n";
×
533
  return extended_density_matrix_reconstructed;
×
534
}
×
535

536
void HardwareMonitor::writeToFile_Topology_with_LinkCost(int qnic_id, double link_cost, double fidelity, double bellpair_per_sec) {
×
537
  auto info = findConnectionInfoByQnicAddr(qnic_id);
×
538
  if (info == nullptr) {
×
539
    error("qnic info not found");
×
540
  }
×
541
  InterfaceInfo interface = getQnicInterfaceByQnicAddr(info->qnic.index, info->qnic.type);
×
542
  cModule *const this_node = provider.getQNode();
×
543
  cModule *const neighbor_node = provider.getNeighborNode(interface.qnic.pointer);
×
544
  const cModuleType *const neighbor_node_type = neighbor_node->getModuleType();
×
545
  cChannel *channel = interface.qnic.pointer->gate("qnic_quantum_port$o")->getNextGate()->getChannel();
×
546
  double dis = channel->par("distance");
×
547
  if (provider.isQNodeType(neighbor_node_type) && provider.isBSANodeType(neighbor_node_type) && provider.isSPDCNodeType(neighbor_node_type)) {
×
548
    error("Module Type not recognized when writing to file...");
×
549
  }
×
550

551
  if (provider.isQNodeType(neighbor_node_type)) {
×
552
    if (my_address > info->neighbor_address) {
×
553
      std::cout << "\n"
×
554
                << this_node->getFullName() << "<--> QuantumChannel{ cost = " << link_cost << "; distance = " << dis << "km; fidelity = " << fidelity
×
555
                << "; bellpair_per_sec = " << bellpair_per_sec << ";} <-->" << neighbor_node->getFullName() << "\n";
×
556
    }
×
557
  } else {
×
558
    std::cout << "\n"
×
559
              << this_node->getFullName() << "<--> QuantumChannel{ cost = " << link_cost << "; distance = " << dis << "km; fidelity = " << fidelity
×
560
              << "; bellpair_per_sec = " << bellpair_per_sec << ";} <-->" << neighbor_node->getFullName() << "\n";
×
561
  }
×
562
}
×
563

564
// Excludes Hom, Epps and other intermediate nodes.
565
QNIC HardwareMonitor::search_QNIC_from_Neighbor_QNode_address(int neighbor_address) {
×
566
  for (auto it = neighbor_table.cbegin(); it != neighbor_table.cend(); ++it) {
×
567
    if (it->second.neighborQNode_address == neighbor_address) {
×
568
      return it->second.qnic;
×
569
    }
×
570
  }
×
571

572
  throw cRuntimeError(
×
573
      "Something is wrong when looking for QNIC info from neighbor QNode "
×
574
      "address. Tomography is also only available between neighbor.");
×
575
}
×
576

577
/**
578
A complex function defining RuleSets for purification and tomography
579
on the link.  This function creates one rule per purification.  As the
580
work proceeds, a resource gets promoted from rule to rule (on
581
purification success), so if you ask for three rounds of purification,
582
it will emit three purification rules.
583

584
For example, with 2002, the first instance of "first stage X
585
purification" (Rule0) includes allocating the resources from the base
586
pair pool, executing the purification circuit (including measurement),
587
exchanging the result messages, comparing and either promoting or
588
discarding, so a one-way classical messaging latency is incurred here.
589

590
Then, the "second stage Z purification" (Rule1, the first time through
591
the loop) begins by drawing two Bell pairs that have each been
592
promoted by the first X purification (rule 0).  An additional one-way
593
latency is incurred here.
594

595
These actions are alternated initial_purification times, for a total
596
of 2n rules (and 2n times the one-way latency).  Note that the
597
semantics of initial_purification vary depending on the
598
purification_type.  In the descriptions below, $n$ is
599
initial_purification.
600

601
Pumping doesn't really work because of the way resources are
602
controlled as they are promoted from rule to rule.  At the moment,
603
base Bell pairs (those created directly by the link) exist in a pool,
604
ordered by age.  Over in Action.cc, you will find
605
Action::getResource_fromTop().  This selects the oldest Bell pair.  At
606
the moment, only the first rule (Rule0) draws from this pool; however,
607
pumping would require that later rules also be able to draw from the
608
pool.
609

610
A purification scheme must be characterized by both the circuit being
611
executed, and the scheduling discipline for selecting the inputs to
612
the circuit.  The scheduling discipline in theory can be pumping,
613
symmetric tree (perfect binary tree), or banded, and should also
614
specify how the resources are sorted.  Currently, this is hard-coded
615
to select oldest first, and is geared toward symmetric tree.
616
  **/
617
void HardwareMonitor::sendLinkTomographyRuleSet(int my_address, int partner_address, QNIC_type qnic_type, int qnic_index, unsigned long RuleSet_id) {
×
618
  LinkTomographyRuleSet *pk = new LinkTomographyRuleSet("LinkTomographyRuleSet");
×
619
  pk->setDestAddr(my_address);
×
620
  pk->setSrcAddr(partner_address);
×
621
  pk->setNumber_of_measuring_resources(num_measure);
×
622
  pk->setKind(6);
×
623

624
  // Tomography between this node and the sender of Ack.
625
  auto *tomography_RuleSet = new RuleSet(RuleSet_id, my_address);
×
626
  EV_INFO << "Creating rules now ruleset_id = " << RuleSet_id << ", partner_address = " << partner_address << "\n";
×
627

628
  int shared_tag = 0;
×
629
  std::string rule_name;
×
630
  std::vector<int> partners = {partner_address};
×
631

632
  if (num_purification > 0) {
×
633
    if (purification_type == 2002) {  // Performs both X and Z purification for each n.
×
634
      /// # Purification_type 2002: #
635
      /// - name: Ss-Sp / perfect binary tree, even rounds
636
      /// - rounds: 2n
637
      /// - input Bell pairs per round: 2
638
      /// - total Bell pairs: 2^(2n)
639
      /// - circuit: Fig. 6.3 in Takaaki's master's thesis
640
      /// - scheduling: symmetric tree
641
      /// ## description: ##
642
      /// Ss-Sp is single selection, single error purification.
643
      /// Between rounds, Hadamard gates are applied
644
      /// to switch basis, creating alternating
645
      /// rounds of X and Z purification.
646
      ///
647
      /// The only difference between 2002 and 3003
648
      /// is the semantics of initial_purification.
649
      /// Here, each iteration results in two rules,
650
      /// guaranteeing an even number of rounds.
651
      ///
652
      /// X always goes first.
653
      /// ![](../img/PhysRevA.100.052320-Fig11.png)
654
      for (int i = 0; i < num_purification; i++) {
×
655
        // First stage X purification
656
        {
×
657
          rule_name = "X purification with: " + std::to_string(partner_address);
×
658
          auto rule = constructPurifyRule(rule_name, PurType::SINGLE_X, partner_address, qnic_type, qnic_index, shared_tag);
×
659
          tomography_RuleSet->addRule(std::move(rule));
×
660
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::SINGLE_X, partner_address, qnic_type, qnic_index, shared_tag++));
×
661
        }
×
662
        // Second stage Z purification (Using X purified resources)
663
        {
×
664
          rule_name = "Z purification with: " + std::to_string(partner_address);
×
665
          auto rule = constructPurifyRule(rule_name, PurType::SINGLE_Z, partner_address, qnic_type, qnic_index, shared_tag);
×
666
          tomography_RuleSet->addRule(std::move(rule));
×
667
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::SINGLE_Z, partner_address, qnic_type, qnic_index, shared_tag++));
×
668
        }
×
669
      }
×
670
    } else if (purification_type == 3003) {
×
671
      /// # Purification_type 3003: #
672
      /// - name: Ss-Sp / perfect binary tree, odd or even rounds
673
      /// - rounds: n
674
      /// - input Bell pairs per round: 2
675
      /// - total Bell pairs: 2^n
676
      /// - circuit: Fig. 6.3 in Takaaki's master's thesis
677
      /// - scheduling: perfect binary (symmetric) tree
678
      /// ## description: ##
679
      /// Ss-Sp is single selection, single error purification.
680
      /// Between rounds, Hadamard gates are applied
681
      /// to switch basis, creating alternating
682
      /// rounds of X and Z purification.
683
      ///
684
      /// The only difference between 2002 and 3003
685
      /// is the semantics of initial_purification.
686
      /// Here, each iteration results in one rule,
687
      /// X for even-numbered rounds (counting from zero),
688
      /// Z for odd-numbered ones, so it is possible to
689
      /// do XZX or XZXZX (but not ZXZ or ZXZXZ).
690
      /// ![](../img/PhysRevA.100.052320-Fig11.png)
691
      // First stage X purification
692
      for (int i = 0; i < num_purification; i++) {
×
693
        std::unique_ptr<Rule> rule;
×
694
        if (i % 2 == 0) {
×
695
          rule_name = "X purification with: " + std::to_string(partner_address);
×
696
          rule = constructPurifyRule(rule_name, PurType::SINGLE_X, partner_address, qnic_type, qnic_index, shared_tag);
×
697
          tomography_RuleSet->addRule(std::move(rule));
×
698
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::SINGLE_X, partner_address, qnic_type, qnic_index, shared_tag++));
×
699
        } else {
×
700
          rule_name = "Z purification with: " + std::to_string(partner_address);
×
701
          rule = constructPurifyRule(rule_name, PurType::SINGLE_Z, partner_address, qnic_type, qnic_index, shared_tag);
×
702
          tomography_RuleSet->addRule(std::move(rule));
×
703
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::SINGLE_Z, partner_address, qnic_type, qnic_index, shared_tag++));
×
704
        }
×
705
      }
×
706
    } else if (purification_type == 1001) {
×
707
      /// # Purification_type 1001: #
708
      /// - name: Ss-Dp XZ Purification
709
      /// - rounds: n
710
      /// - input Bell pairs per round: 3
711
      /// - total Bell pairs: 3^n
712
      /// - circuit: Fig. 12 in arXiv:1904.08605
713
      /// - scheduling: symmetric tree
714
      /// ## description: ##
715
      /// Both X and Z purification in a single action.  If A
716
      /// is the pair being purified, and C and E are tools,
717
      /// CNOT(A,C), MEAS(C), CNOT(E,A), MEAS(E)
718
      /// then select after comparing outcomes.
719
      /// Note that bases are not flipped between rounds.
720
      /// Similar to 1221.
721
      /// ![](../img/PhysRevA.100.052320-Fig12.png)
722
      for (int i = 0; i < num_purification; i++) {
×
723
        rule_name = "Double purification with: " + std::to_string(partner_address);
×
724
        auto rule = constructPurifyRule(rule_name, PurType::DOUBLE, partner_address, qnic_type, qnic_index, shared_tag);
×
725
        tomography_RuleSet->addRule(std::move(rule));
×
726
        tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DOUBLE, partner_address, qnic_type, qnic_index, shared_tag++));
×
727
      }
×
728
    } else if (purification_type == 1221) {
×
729
      /// # Purification_type 1221: #
730
      /// - name: Ss-Dp XZ, ZX alternating
731
      /// - rounds: n
732
      /// - input Bell pairs per round: 3
733
      /// - total Bell pairs: 3^n
734
      /// - circuit: *almost* Fig. 12 from arXiv:1904.08605, but order
735
      /// of CNOTs reversed in alternating rounds
736
      /// - scheduling: symmetric tree
737
      /// ## description: ##
738
      /// Almost the same as 1001, but first round
739
      /// is XZ, second round is ZX.  Results in better alternating
740
      /// error suppression, but still not great.
741
      /// ![](../img/PhysRevA.100.052320-Fig12.png)
742
      for (int i = 0; i < num_purification; i++) {
×
743
        std::unique_ptr<Rule> rule;
×
744
        if (i % 2 == 0) {
×
745
          rule_name = "Double purification with: " + std::to_string(partner_address);
×
746
          rule = constructPurifyRule(rule_name, PurType::DOUBLE, partner_address, qnic_type, qnic_index, shared_tag);
×
747
          tomography_RuleSet->addRule(std::move(rule));
×
748
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DOUBLE, partner_address, qnic_type, qnic_index, shared_tag++));
×
749
        } else {
×
750
          rule_name = "Double purification Inverse with: " + std::to_string(partner_address);
×
751
          rule = constructPurifyRule(rule_name, PurType::DOUBLE_INV, partner_address, qnic_type, qnic_index, shared_tag);
×
752
          tomography_RuleSet->addRule(std::move(rule));
×
753
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DOUBLE_INV, partner_address, qnic_type, qnic_index, shared_tag++));
×
754
        }
×
755
      }
×
756
    } else if (purification_type == 1011) {
×
757
      /// # Purification_type 1011: #
758
      /// - name: Ds-Sp: Fujii-san's Double selection purification
759
      /// - rounds: n
760
      /// - input Bell pairs per round: 3
761
      /// - total Bell pairs: 3^n
762
      /// - circuit: Fig. 13 in arXiv:1904.08605
763
      /// - scheduling: symmetric tree
764
      /// ## description: ##
765
      /// Similar to 1001 and 1221 except that the control and target
766
      /// of the first CNOT are flipped, corresponding to Fujii-san's
767
      /// paper (PRA 80, 042308).
768
      /// Every round is identical.
769
      /// Note there is no basis change between rounds.
770
      /// ![](../img/arxiv.1904.08605-Fig13.png)
771
      for (int i = 0; i < num_purification; i++) {
×
772
        rule_name = "Double Selection with: " + std::to_string(partner_address);
×
773
        auto rule = constructPurifyRule(rule_name, PurType::DSSA, partner_address, qnic_type, qnic_index, shared_tag);
×
774
        tomography_RuleSet->addRule(std::move(rule));
×
775
        tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DSSA, partner_address, qnic_type, qnic_index, shared_tag++));
×
776
      }
×
777
    } else if (purification_type == 1021) {  // Fujii-san's Double selection purification
×
778
      /// # Purification_type 1021: #
779
      /// - name: Ds-Sp: Fujii-san's Double selection purification (alternating)
780
      /// - rounds: n
781
      /// - input Bell pairs per round: 3
782
      /// - total Bell pairs: 3^n
783
      /// - circuit: *almost* Fig. 13 in arXiv:1904.08605, except that
784
      /// the order of the CNOTs alternates between rounds
785
      /// - scheduling: symmetric tree
786
      /// ## description: ##
787
      /// Similar to 1011, almost corresponding to Fujii-san's paper (PRA 80,
788
      /// 042308). Note there is no basis change between rounds, but that the
789
      /// first round is XZ, second is ZX.
790
      /// ![](../img/arxiv.1904.08605-Fig13.png)
791
      for (int i = 0; i < num_purification; i++) {
×
792
        std::unique_ptr<Rule> rule;
×
793
        if (i % 2 == 0) {
×
794
          rule_name = "Double selection with: " + std::to_string(partner_address);
×
795
          rule = constructPurifyRule(rule_name, PurType::DSSA, partner_address, qnic_type, qnic_index, shared_tag);
×
796
          tomography_RuleSet->addRule(std::move(rule));
×
797
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DSSA, partner_address, qnic_type, qnic_index, shared_tag++));
×
798
        } else {
×
799
          rule_name = "Double selection Inverse with: " + std::to_string(partner_address);
×
800
          rule = constructPurifyRule(rule_name, PurType::DSSA_INV, partner_address, qnic_type, qnic_index, shared_tag);
×
801
          tomography_RuleSet->addRule(std::move(rule));
×
802
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DSSA_INV, partner_address, qnic_type, qnic_index, shared_tag++));
×
803
        }
×
804
      }
×
805
    } else if (purification_type == 1031) {
×
806
      /// # Purification_type 1031: #
807
      /// - name: Ds-Dp: full double selection purification (alternating)
808
      /// - rounds: n
809
      /// - input Bell pairs per round: 5
810
      /// - total Bell pairs: 5^n
811
      /// - circuit: Fig. 14 in arXiv:1904.08605, except that
812
      /// the order of the CNOTs alternates between rounds
813
      /// - scheduling: symmetric tree
814
      /// ## description: ##
815
      /// A combination of 1001 and 1011 (Figs. 12 & 13).  Resource requirements
816
      /// are high; two rounds of this requires 25 Bell pairs.  With a low base
817
      /// Bell pair generation rate and realistic memory decoherence, this will
818
      /// be impractical.
819
      /// ![](../img/arxiv.1904.08605-Fig14.png)
820
      for (int i = 0; i < num_purification; i++) {
×
821
        std::unique_ptr<Rule> rule;
×
822
        if (i % 2 == 0) {
×
823
          rule_name = "Double selection Dual action with: " + std::to_string(partner_address);
×
824
          rule = constructPurifyRule(rule_name, PurType::DSDA, partner_address, qnic_type, qnic_index, shared_tag);
×
825
          tomography_RuleSet->addRule(std::move(rule));
×
826
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DSSA, partner_address, qnic_type, qnic_index, shared_tag++));
×
827
        } else {
×
828
          rule_name = "Double selection Dual action Inverse with: " + std::to_string(partner_address);
×
829
          rule = constructPurifyRule(rule_name, PurType::DSDA_INV, partner_address, qnic_type, qnic_index, shared_tag);
×
830
          tomography_RuleSet->addRule(std::move(rule));
×
831
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DSSA_INV, partner_address, qnic_type, qnic_index, shared_tag++));
×
832
        }
×
833
      }
×
834
    } else if (purification_type == 1061) {
×
835
      /// # Purification_type 1061: #
836
      /// - name: half double selection, half single selection
837
      /// - rounds: n
838
      /// - input Bell pairs per round: 4
839
      /// - total Bell pairs: 4^n
840
      /// - circuit: no figure available
841
      /// - scheduling: symmetric tree
842
      /// ## description: ##
843
      /// Does double selection on X, single selection on Z
844
      /// Switches bases between rounds.
845
      /// Investigated for possibly highly asymmetric X/Z error rates in base
846
      /// Bell pairs. Initial results weren't very promised, not extensively
847
      /// used.
848
      for (int i = 0; i < num_purification; i++) {
×
849
        std::unique_ptr<Rule> rule;
×
850
        if (i % 2 == 0) {
×
851
          rule_name = "Double selection Dual action second with: " + std::to_string(partner_address);
×
852
          rule = constructPurifyRule(rule_name, PurType::DSDA_SECOND, partner_address, qnic_type, qnic_index, shared_tag);
×
853
          tomography_RuleSet->addRule(std::move(rule));
×
854
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DSDA_SECOND, partner_address, qnic_type, qnic_index, shared_tag++));
×
855
        } else {
×
856
          rule_name = "Double selection Dual action second inverse with: " + std::to_string(partner_address);
×
857
          rule = constructPurifyRule(rule_name, PurType::DSDA_SECOND_INV, partner_address, qnic_type, qnic_index, shared_tag);
×
858
          tomography_RuleSet->addRule(std::move(rule));
×
859
          tomography_RuleSet->addRule(
×
860
              constructCorrelationCheckRule("purification correlation check", PurType::DSDA_SECOND_INV, partner_address, qnic_type, qnic_index, shared_tag++));
×
861
        }
×
862
      }
×
863
    } else if (purification_type == 5555) {  // Predefined purification method
×
864
      /// # Purification_type 5555: #
865
      /// - name: Switching (B)
866
      /// - rounds: n
867
      /// - input Bell pairs per round: 3 in first two rounds, then 2
868
      /// - total Bell pairs: (complicated)
869
      /// - circuit: Fig. 21, case B in arXiv:1904.08605
870
      /// - scheduling: symmetric tree (*)
871
      /// ## description: ##
872
      /// Two rounds of Ds-Sp, then Ss-Sp.
873
      /// The point of this was to show that you don't have to stick with one
874
      /// scheme, but can use different schemes in different rounds.
875
      for (int i = 0; i < 2; i++) {
×
876
        if (i % 2 == 0) {
×
877
          rule_name = "Double selection action with: " + std::to_string(partner_address);
×
878
        } else {
×
879
          rule_name = "Double selection action inverse with: " + std::to_string(partner_address);
×
880
        }
×
881
        auto rule = std::make_unique<Rule>(my_address, shared_tag, shared_tag);
×
882
        rule->setName(rule_name);
×
883
        auto condition = std::make_unique<Condition>();
×
884
        auto resource_clause = std::make_unique<EnoughResourceConditionClause>(3, partner_address);
×
885
        condition->addClause(std::move(resource_clause));
×
886
        rule->setCondition(std::move(condition));
×
887
        if (i % 2 == 0) {
×
888
          auto purify_action = std::make_unique<Purification>(PurType::DSSA, partner_address, shared_tag);
×
889
          rule->setAction(std::move(purify_action));
×
890
          tomography_RuleSet->addRule(std::move(rule));
×
891
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DSSA, partner_address, qnic_type, qnic_index, shared_tag++));
×
892
        } else {
×
893
          auto purify_action = std::make_unique<Purification>(PurType::DSDA_INV, partner_address, shared_tag);
×
894
          rule->setAction(std::move(purify_action));
×
895
          tomography_RuleSet->addRule(std::move(rule));
×
896
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DSDA_INV, partner_address, qnic_type, qnic_index, shared_tag++));
×
897
        }
×
898
      }
×
899

900
      for (int i = 0; i < num_purification; i++) {
×
901
        std::unique_ptr<Rule> rule;
×
902
        if (i % 2 == 0) {
×
903
          rule_name = "X Purification with: " + std::to_string(partner_address);
×
904
          rule = constructPurifyRule(rule_name, PurType::SINGLE_X, partner_address, qnic_type, qnic_index, shared_tag);
×
905
          tomography_RuleSet->addRule(std::move(rule));
×
906
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::SINGLE_X, partner_address, qnic_type, qnic_index, shared_tag++));
×
907
        } else {
×
908
          rule_name = "Z Purification with: " + std::to_string(partner_address);
×
909
          rule = constructPurifyRule(rule_name, PurType::SINGLE_Z, partner_address, qnic_type, qnic_index, shared_tag);
×
910
          tomography_RuleSet->addRule(std::move(rule));
×
911
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::SINGLE_Z, partner_address, qnic_type, qnic_index, shared_tag++));
×
912
        }
×
913
      }
×
914
    } else if (purification_type == 5556) {  // Predefined purification method
×
915
      /// # Purification_type 5556: #
916
      /// - name: Switching (A)
917
      /// - rounds: n
918
      /// - input Bell pairs per round: 3 in first round, then 2
919
      /// - total Bell pairs: (complicated)
920
      /// - circuit: Fig. 21, case A in arXiv:1904.08605
921
      /// - scheduling: symmetric tree (*)
922
      /// ## description: ##
923
      /// One round of Ds-Sp, then Ss-Sp.
924
      /// The point of this was to show that you don't have to stick with one
925
      /// scheme, but can use different schemes in different rounds.
926
      rule_name = "Double selection action with: " + std::to_string(partner_address);
×
927
      auto rule = constructPurifyRule(rule_name, PurType::DSSA, partner_address, qnic_type, qnic_index, shared_tag);
×
928
      tomography_RuleSet->addRule(std::move(rule));
×
929
      tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::DSSA, partner_address, qnic_type, qnic_index, shared_tag++));
×
930

931
      for (int i = 0; i < num_purification; i++) {
×
932
        std::unique_ptr<Rule> rule;
×
933
        if (i % 2 == 0) {
×
934
          rule_name = "Z purification with: " + std::to_string(partner_address);
×
935
          rule = constructPurifyRule(rule_name, PurType::SINGLE_Z, partner_address, qnic_type, qnic_index, shared_tag);
×
936
          tomography_RuleSet->addRule(std::move(rule));
×
937
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::SINGLE_Z, partner_address, qnic_type, qnic_index, shared_tag++));
×
938
        } else {
×
939
          rule_name = "X purification with: " + std::to_string(partner_address);
×
940
          rule = constructPurifyRule(rule_name, PurType::SINGLE_X, partner_address, qnic_type, qnic_index, shared_tag);
×
941
          tomography_RuleSet->addRule(std::move(rule));
×
942
          tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", PurType::SINGLE_X, partner_address, qnic_type, qnic_index, shared_tag++));
×
943
        }
×
944
      }
×
945
    } else if ((X_Purification && !Z_Purification) || (!X_Purification && Z_Purification)) {  // X or Z purification. Out-dated syntax.
×
946
      /// # Purification_type default: #
947
      /// - name: Boolean-driven (obsolete)
948
      /// - rounds: 1
949
      /// - input Bell pairs: 2 or 3
950
      /// - total Bell pairs: 2 or 3
951
      /// - circuit: <reference a figure>
952
      /// - scheduling: (commonly pumping, symmetric tree, or banded)
953
      /// ## description: ##
954
      /// uses X_Purification and Z_purification booleans, but is obsolete.
955
      /// Creates a single purification only, or a single round of double
956
      /// purification. Use of this for new work is deprecated.
957
      rule_name = "Single purification with: " + std::to_string(partner_address);
×
958
      auto rule = constructPurifyRule(rule_name, (X_Purification ? PurType::SINGLE_X : PurType::SINGLE_Z), partner_address, qnic_type, qnic_index, shared_tag);
×
959
      tomography_RuleSet->addRule(std::move(rule));
×
960
      tomography_RuleSet->addRule(constructCorrelationCheckRule("purification correlation check", (X_Purification ? PurType::SINGLE_X : PurType::SINGLE_Z), partner_address,
×
961
                                                                qnic_type, qnic_index, shared_tag++));
×
962
    } else {  // X, Z double purification
×
963
      error("syntax outdate or purification id not recognized.");
×
964
    }
×
965

966
    // Let's make nodes select measurement basis randomly, because it it easier.
967
    auto rule = std::make_unique<Rule>(my_address, shared_tag, shared_tag);
×
968
    rule->setName("tomography");
×
969

970
    auto condition = std::make_unique<Condition>();
×
971

972
    // 1 qubit resource required to perform tomography action
973
    auto res_check_clause = std::make_unique<EnoughResourceConditionClause>(1, partner_address);
×
974
    condition->addClause(std::move(res_check_clause));
×
975

976
    // 3000 measurements in total. There are 3*3 = 9 patterns of measurements.
977
    // So each combination must perform 3000/9 measurements.
978
    auto measure_count_clause = std::make_unique<MeasureCountConditionClause>(num_measure, partner_address);
×
979
    condition->addClause(std::move(measure_count_clause));
×
980
    rule->setCondition(std::move(condition));
×
981

982
    // Measure the local resource between it->second.neighborQNode_address.
983
    auto measure_action = std::make_unique<Tomography>(num_measure, my_address, partner_address);
×
984
    measure_action->start_time = simTime();
×
985
    rule->setAction(std::move(measure_action));
×
986

987
    tomography_RuleSet->addRule(std::move(rule));
×
988
    pk->setRuleSet(tomography_RuleSet);
×
989
    send(pk, "RouterPort$o");
×
990
  } else {
×
991
    // RuleSet with no purification. Pure measurement only link level tomography.
992

993
    auto rule = std::make_unique<Rule>(my_address, shared_tag, shared_tag);
×
994
    auto condition = std::make_unique<Condition>();
×
995
    auto res_check_clause = std::make_unique<EnoughResourceConditionClause>(1, partner_address);
×
996
    auto measure_count_clause = std::make_unique<MeasureCountConditionClause>(num_measure, partner_address);
×
997
    condition->addClause(std::move(res_check_clause));
×
998
    condition->addClause(std::move(measure_count_clause));
×
999
    rule->setCondition(std::move(condition));
×
1000

1001
    // Measure the local resource between it->second.neighborQNode_address.
1002
    auto measure = std::make_unique<Tomography>(num_measure, my_address, partner_address);
×
1003
    measure->start_time = simTime();
×
1004
    rule->setAction(std::move(measure));
×
1005

1006
    tomography_RuleSet->addRule(std::move(rule));
×
1007

1008
    pk->setRuleSet(tomography_RuleSet);
×
1009
    send(pk, "RouterPort$o");
×
1010
  }
×
1011
}
×
1012

1013
std::unique_ptr<Rule> HardwareMonitor::constructPurifyRule(const std::string &rule_name, const rules::PurType pur_type, const int partner_address, const QNIC_type qnic_type,
1014
                                                           const int qnic_index, const int send_tag) const {
×
1015
  int required_qubits = 0;
×
1016
  switch (pur_type) {
×
1017
    case PurType::SINGLE_X:
×
1018
    case PurType::SINGLE_Z:
×
1019
    case PurType::SINGLE_Y:
×
1020
      required_qubits = 2;
×
1021
      break;
×
1022
    case PurType::DOUBLE:
×
1023
    case PurType::DOUBLE_INV:
×
1024
    case PurType::DSSA:
×
1025
    case PurType::DSSA_INV:
×
1026
      required_qubits = 3;
×
1027
      break;
×
1028
    case PurType::DSDA:
×
1029
    case PurType::DSDA_INV:
×
1030
      required_qubits = 5;
×
1031
      break;
×
1032
    case PurType::DSDA_SECOND:
×
1033
    case PurType::DSDA_SECOND_INV:
×
1034
      required_qubits = 4;
×
1035
      break;
×
1036
    case PurType::INVALID:
×
1037
    default:
×
1038
      error("got invalid purification type");
×
1039
  }
×
1040
  auto rule = std::make_unique<Rule>(my_address, send_tag, -1);
×
1041
  rule->setName(rule_name);
×
1042
  auto condition = std::make_unique<Condition>();
×
1043
  auto resource_clause = std::make_unique<EnoughResourceConditionClause>(required_qubits, partner_address);
×
1044
  condition->addClause(std::move(resource_clause));
×
1045
  rule->setCondition(std::move(condition));
×
1046
  auto purify_action = std::make_unique<Purification>(pur_type, partner_address, send_tag);
×
1047
  rule->setAction(std::move(purify_action));
×
1048
  return rule;
×
1049
}
×
1050

1051
std::unique_ptr<Rule> HardwareMonitor::constructCorrelationCheckRule(const std::string &rule_name, const rules::PurType pur_type, const int partner_address,
1052
                                                                     const QNIC_type qnic_type, const int qnic_index, const int receive_tag) const {
×
1053
  auto correlation_rule = std::make_unique<Rule>(partner_address, -1, receive_tag);
×
1054

1055
  auto condition = std::make_unique<Condition>();
×
1056
  auto correlation_clause = std::make_unique<PurificationCorrelationClause>(partner_address, receive_tag);
×
1057
  condition->addClause(std::move(correlation_clause));
×
1058

1059
  auto action = std::make_unique<PurificationCorrelation>(partner_address, receive_tag);
×
1060

1061
  correlation_rule->setCondition(std::move(condition));
×
1062
  correlation_rule->setAction(std::move(action));
×
1063
  return correlation_rule;
×
1064
}
×
1065

1066
int HardwareMonitor::getQnicNumQubits(int qnic_index, QNIC_type qnic_type) {
×
1067
  Enter_Method("checkNumBuff()");
×
1068
  auto qnic = getQnic(qnic_index, qnic_type);
×
1069
  return qnic->par("num_buffer");
×
1070
}
×
1071

1072
cModule *HardwareMonitor::getQnic(int qnic_index, QNIC_type qnic_type) {
×
1073
  if (qnic_type >= QNIC_N) {
×
1074
    error("invalid qnic type: %d", qnic_type);
×
1075
  }
×
1076

1077
  cModule *qnic = provider.getQNode()->getSubmodule(QNIC_names[qnic_type], qnic_index);
×
1078
  if (qnic == nullptr) {
×
1079
    error("qnic(index: %d) not found.", qnic_index);
×
1080
  }
×
1081
  return qnic;
×
1082
}
×
1083

1084
InterfaceInfo HardwareMonitor::getQnicInterfaceByQnicAddr(int qnic_index, QNIC_type qnic_type) {
×
1085
  cModule *local_qnic = getQnic(qnic_index, qnic_type);
×
1086
  InterfaceInfo inf;
×
1087
  inf.qnic.pointer = local_qnic;
×
1088
  inf.qnic.address = local_qnic->par("self_qnic_address");
×
1089
  inf.qnic.index = qnic_index;
×
1090
  inf.qnic.type = qnic_type;
×
1091
  inf.buffer_size = local_qnic->par("num_buffer");
×
1092

1093
  // Just read link cost from channel parameter for now as a dummy (or as an initialization).
1094
  // int cost = local_qnic->gate("qnic_quantum_port$o")->getNextGate()->getChannel()->par("cost");
1095
  // This is false because the channel may only be between the node and BSA.
1096

1097
  // Dummy it up. This cost must be the cost based on the neighboring QNode
1098
  // (excluding SPDC and BSA nodes)
1099
  inf.link_cost = 1;
×
1100

1101
  return inf;
×
1102
}
×
1103

1104
std::unique_ptr<ConnectionSetupInfo> HardwareMonitor::findConnectionInfoByQnicAddr(int qnic_address) {
×
1105
  for (auto it = neighbor_table.cbegin(); it != neighbor_table.cend(); ++it) {
×
1106
    if (it->second.qnic.address == qnic_address) {
×
1107
      auto info = std::make_unique<ConnectionSetupInfo>();
×
1108
      info->qnic.type = it->second.qnic.type;
×
1109
      info->qnic.index = it->second.qnic.index;
×
1110
      info->qnic.address = it->second.qnic.address;
×
1111
      info->neighbor_address = it->second.neighborQNode_address;
×
1112
      info->quantum_link_cost = it->second.link_cost;
×
1113
      return info;
×
1114
    }
×
1115
  }
×
1116
  return nullptr;
×
1117
}
×
1118

1119
// This neighbor table includes all neighbors of qnic, qnic_r and qnic_rp
1120
void HardwareMonitor::prepareNeighborTable() {
×
1121
  // Traverse through all local qnics to check where they are connected to.
1122
  // BSA and EPPS will be ignored in this case.
1123
  for (int index = 0; index < num_qnic; index++) {
×
1124
    InterfaceInfo inf = getQnicInterfaceByQnicAddr(index, QNIC_E);
×
1125
    auto n_inf = getNeighbor(inf.qnic.pointer);
×
1126
    int neighborNodeAddress = n_inf->address;  // get the address of the Node nearby.
×
1127
    inf.neighborQNode_address = n_inf->neighborQNode_address;
×
1128
    neighbor_table[neighborNodeAddress] = inf;
×
1129
  }
×
1130
  for (int index = 0; index < num_qnic_r; index++) {
×
1131
    InterfaceInfo inf = getQnicInterfaceByQnicAddr(index, QNIC_R);
×
1132
    auto n_inf = getNeighbor(inf.qnic.pointer);
×
1133
    int neighborNodeAddress = n_inf->address;  // get the address of the Node nearby.
×
1134
    inf.neighborQNode_address = n_inf->neighborQNode_address;
×
1135
    neighbor_table[neighborNodeAddress] = inf;
×
1136
  }
×
1137
  for (int index = 0; index < num_qnic_rp; index++) {
×
1138
    InterfaceInfo inf = getQnicInterfaceByQnicAddr(index, QNIC_RP);
×
1139
    auto n_inf = getNeighbor(inf.qnic.pointer);
×
1140
    int neighborNodeAddress = n_inf->address;  // get the address of the Node nearby.
×
1141
    inf.neighborQNode_address = n_inf->neighborQNode_address;
×
1142
    neighbor_table[neighborNodeAddress] = inf;
×
1143
  }
×
1144
}
×
1145

1146
// This method finds out the address of the neighboring node with respect to the
1147
// local unique qnic address.
1148
std::unique_ptr<NeighborInfo> HardwareMonitor::getNeighbor(cModule *qnic_module) {
×
1149
  // qnic_quantum_port$o is connected to the node's outermost quantum_port
1150
  cGate *gate = qnic_module->gate("qnic_quantum_port$o")->getNextGate();
×
1151
  cGate *neighbor_gate = gate->getNextGate();
×
1152

1153
  // Owner could be BSA, EPPS, QNode
1154
  const cModule *neighbor_node = neighbor_gate->getOwnerModule();
×
1155
  if (neighbor_node == nullptr) {
×
1156
    error("neighbor node not found.");
×
1157
  }
×
1158
  auto neighbor_info = createNeighborInfo(*neighbor_node);
×
1159
  return neighbor_info;
×
1160
}
×
1161

1162
cModule *HardwareMonitor::getQNodeWithAddress(int address) {
×
1163
  cTopology *topo = new cTopology("topo");
×
1164
  // veryfication?
1165
  topo->extractByParameter("included_in_topology", "\"yes\"");
×
1166
  int addr;
×
1167
  for (int i = 0; i < topo->getNumNodes(); i++) {
×
1168
    cTopology::Node *node = topo->getNode(i);
×
1169
    addr = (int)node->getModule()->par("address");
×
1170
    EV_DEBUG << "End node address is " << addr << "\n";
×
1171
    if (addr == address) {
×
1172
      auto *mod = node->getModule();
×
1173
      delete topo;
×
1174
      return mod;
×
1175
    }
×
1176
  }
×
1177
  delete topo;
×
1178
}
×
1179

1180
std::unique_ptr<NeighborInfo> HardwareMonitor::createNeighborInfo(const cModule &thisNode) {
×
1181
  cModuleType *type = thisNode.getModuleType();
×
1182

1183
  auto inf = std::make_unique<NeighborInfo>();
×
1184
  inf->type = type;
×
1185
  inf->address = thisNode.par("address");
×
1186

1187
  if (provider.isQNodeType(type)) {
×
1188
    inf->neighborQNode_address = thisNode.par("address");
×
1189
    inf->address = thisNode.par("address");
×
1190
    return inf;
×
1191
  }
×
1192

1193
  if (provider.isBSANodeType(type)) {
×
1194
    auto *controller = dynamic_cast<BSAController *>(thisNode.getSubmodule("bsa_controller"));
×
1195
    if (controller == nullptr) {
×
1196
      error("BSA controller not found");
×
1197
    }
×
1198

1199
    int address_one = controller->getExternalAdressFromPort(0);
×
1200
    int address_two = controller->getExternalAdressFromPort(1);
×
1201
    int myaddress = par("address");
×
1202

1203
    EV_DEBUG << "myaddress = " << myaddress << ", address = " << address_one << ", address_two = " << address_two << " in " << controller->getFullName() << "\n";
×
1204

1205
    if (address_one == -1 && address_two == -1) {
×
1206
      error("BSA Controller is not initialized properly");
×
1207
    }
×
1208

1209
    if (address_one == myaddress) {
×
1210
      inf->neighborQNode_address = address_two;
×
1211
    } else if (address_two == myaddress) {
×
1212
      inf->neighborQNode_address = address_one;
×
1213
    }
×
1214

1215
    return inf;
×
1216
  }
×
1217

1218
  if (provider.isSPDCNodeType(type)) {
×
1219
    error("TO BE IMPLEMENTED");
×
1220
  }
×
1221

1222
  error(
×
1223
      "This simulator only recognizes the following network level node "
×
1224
      "types: QNode, EPPS and BSA. Not %s",
×
1225
      thisNode.getClassName());
×
1226
}
×
1227

1228
NeighborTable HardwareMonitor::passNeighborTable() {
×
1229
  Enter_Method("passNeighborTable()");
×
1230
  return neighbor_table;
×
1231
}
×
1232

1233
}  // namespace quisp::modules
1234

1235
namespace std {
1236
std::stringstream &operator<<(std::stringstream &os, const quisp::modules::NeighborInfo &v) {
×
1237
  os << "neighborInfo(addr: " << v.address << ", neighborQNodeAddr: " << v.neighborQNode_address;
×
1238
  return os;
×
1239
}
×
1240
std::basic_ostream<char> &operator<<(std::basic_ostream<char> &os, const quisp::modules::InterfaceInfo &v) {
×
1241
  os << "InterfaceInf(neighborQNodeAddr: " << v.neighborQNode_address << ", qnic.addr: " << v.qnic.address << ")";
×
1242
  return os;
×
1243
}
×
1244
}  // namespace std
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc