• 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

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

7
#include <cassert>
8
#include <fstream>
9
#include <iterator>
10
#include <memory>
11
#include <stdexcept>
12
#include <utility>
13

14
#include "QNicStore/QNicStore.h"
15
#include "RuntimeCallback.h"
16
#include "modules/PhysicalConnection/BSA/types.h"
17

18
namespace quisp::modules {
19

20
using namespace rules;
21
using namespace messages;
22
using qnic_store::QNicStore;
23
using runtime_callback::RuntimeCallback;
24

25
RuleEngine::RuleEngine() : provider(utils::ComponentProvider{this}), runtimes(std::make_unique<RuntimeCallback>(this)) {}
6✔
26

27
RuleEngine::~RuleEngine() {
×
28
  for (int i = 0; i < number_of_qnics; i++) cancelAndDelete(emit_photon_timer_map[{QNIC_type::QNIC_E, i}]);
×
29
  for (int i = 0; i < number_of_qnics_r; i++) cancelAndDelete(emit_photon_timer_map[{QNIC_type::QNIC_R, i}]);
×
30
  for (int i = 0; i < number_of_qnics_rp; i++) cancelAndDelete(emit_photon_timer_map[{QNIC_type::QNIC_RP, i}]);
×
31
}
×
32

33
void RuleEngine::initialize() {
6✔
34
  // HardwareMonitor's neighbor table is checked in the initialization stage of the simulation
35
  // This assumes the topology never changes throughout the simulation.
36
  // If dynamic change in topology is required, recoding this is needed.
37
  hardware_monitor = provider.getHardwareMonitor();
6✔
38
  realtime_controller = provider.getRealTimeController();
6✔
39
  routingdaemon = provider.getRoutingDaemon();
6✔
40
  initializeLogger(provider);
6✔
41
  bell_pair_store.logger = logger;
6✔
42

43
  parentAddress = par("address");
6✔
44
  number_of_qnics_all = par("total_number_of_qnics");
6✔
45
  number_of_qnics = par("number_of_qnics");
6✔
46
  number_of_qnics_r = par("number_of_qnics_r");
6✔
47
  number_of_qnics_rp = par("number_of_qnics_rp");
6✔
48
  if (qnic_store == nullptr) {
6✔
49
    qnic_store = std::make_unique<QNicStore>(provider, number_of_qnics, number_of_qnics_r, number_of_qnics_rp, logger);
4✔
50
  }
4✔
51
  for (int i = 0; i < number_of_qnics; i++) {
20✔
52
    emit_photon_timer_map[{QNIC_type::QNIC_E, i}] = new EmitPhotonRequest();
14✔
53
    emit_photon_timer_map[{QNIC_type::QNIC_E, i}]->setQnicType(QNIC_type::QNIC_E);
14✔
54
    emit_photon_timer_map[{QNIC_type::QNIC_E, i}]->setQnicIndex(i);
14✔
55
  }
14✔
56
  for (int i = 0; i < number_of_qnics_r; i++) {
12✔
57
    emit_photon_timer_map[{QNIC_type::QNIC_R, i}] = new EmitPhotonRequest();
6✔
58
    emit_photon_timer_map[{QNIC_type::QNIC_R, i}]->setQnicType(QNIC_type::QNIC_R);
6✔
59
    emit_photon_timer_map[{QNIC_type::QNIC_R, i}]->setQnicIndex(i);
6✔
60
  }
6✔
61
  for (int i = 0; i < number_of_qnics_rp; i++) {
6✔
62
    emit_photon_timer_map[{QNIC_type::QNIC_RP, i}] = new EmitPhotonRequest();
×
63
    emit_photon_timer_map[{QNIC_type::QNIC_RP, i}]->setQnicType(QNIC_type::QNIC_RP);
×
64
    emit_photon_timer_map[{QNIC_type::QNIC_RP, i}]->setQnicIndex(i);
×
65
  }
×
66
}
6✔
67

68
void RuleEngine::handleMessage(cMessage *msg) {
7✔
69
  executeAllRuleSets();  // New resource added to QNIC with qnic_type qnic_index.
7✔
70

71
  if (auto *notification_packet = dynamic_cast<BSMTimingNotification *>(msg)) {
7✔
72
    if (auto *bsa_results = dynamic_cast<CombinedBSAresults *>(msg)) {
×
73
      handleLinkGenerationResult(bsa_results);
×
74
    }
×
75
    auto type = notification_packet->getQnicType();
×
76
    auto qnic_index = notification_packet->getQnicIndex();
×
77
    stopOnGoingPhotonEmission(type, qnic_index);
×
78
    freeFailedEntanglementAttemptQubits(type, qnic_index);
×
79
    schedulePhotonEmission(type, qnic_index, notification_packet);
×
80
  } else if (auto *pk = dynamic_cast<EmitPhotonRequest *>(msg)) {
7✔
81
    auto type = pk->getQnicType();
7✔
82
    auto qnic_index = pk->getQnicIndex();
7✔
83
    auto number_of_free_emitters = qnic_store->countNumFreeQubits(type, qnic_index);
7✔
84
    auto is_first = pk->isFirst();
7✔
85
    auto is_last = (number_of_free_emitters == 1);
7✔
86
    auto qubit_index = qnic_store->takeFreeQubitIndex(type, qnic_index);
7✔
87

88
    if (number_of_free_emitters == 0) return;
7✔
89

90
    // need to set is_first to false
91
    pk->setFirst(false);
6✔
92
    sendEmitPhotonSignalToQnic(type, qnic_index, qubit_index, is_first, is_last);
6✔
93
    if (!is_last) {
6✔
94
      scheduleAt(simTime() + pk->getIntervalBetweenPhotons(), pk);
3✔
95
    }
3✔
96
    // early return since this doesn't affect entangled resource
97
    // and we don't want to delete these messages
98
    return;
6✔
99
  } else if (auto *pk = dynamic_cast<LinkTomographyRuleSet *>(msg)) {
7✔
100
    auto *ruleset = pk->getRuleSet();
×
101
    runtimes.acceptRuleSet(ruleset->construct());
×
102
  } else if (auto *pkt = dynamic_cast<PurificationResult *>(msg)) {
×
103
    handlePurificationResult(pkt);
×
104
  } else if (auto *pkt = dynamic_cast<SwappingResult *>(msg)) {
×
105
    handleSwappingResult(pkt);
×
106
  } else if (auto *pkt = dynamic_cast<InternalRuleSetForwarding *>(msg)) {
×
107
    // add actual process
108
    auto serialized_ruleset = pkt->getRuleSet();
×
109
    RuleSet ruleset(0, 0);
×
110
    ruleset.deserialize_json(serialized_ruleset);
×
111
    runtimes.acceptRuleSet(ruleset.construct());
×
112
  } else if (auto *pkt = dynamic_cast<InternalRuleSetForwarding_Application *>(msg)) {
×
113
    if (pkt->getApplication_type() != 0) error("This application is not recognized yet");
×
114
    auto serialized_ruleset = pkt->getRuleSet();
×
115
    RuleSet ruleset(0, 0);
×
116
    ruleset.deserialize_json(serialized_ruleset);
×
117
    runtimes.acceptRuleSet(ruleset.construct());
×
118
  }
×
119

120
  for (int i = 0; i < number_of_qnics; i++) {
×
121
    ResourceAllocation(QNIC_E, i);
×
122
  }
×
123
  for (int i = 0; i < number_of_qnics_r; i++) {
×
124
    ResourceAllocation(QNIC_R, i);
×
125
  }
×
126
  for (int i = 0; i < number_of_qnics_rp; i++) {
×
127
    ResourceAllocation(QNIC_RP, i);
×
128
  }
×
129

130
  executeAllRuleSets();
×
131
  delete msg;
×
132
}
×
133

134
void RuleEngine::schedulePhotonEmission(QNIC_type type, int qnic_index, BSMTimingNotification *notification) {
×
135
  auto first_photon_emit_time = getEmitTimeFromBSMNotification(notification);
×
136
  auto *timer = emit_photon_timer_map[{type, qnic_index}];
×
137
  timer->setFirst(true);
×
138
  timer->setIntervalBetweenPhotons(notification->getInterval());
×
139
  scheduleAt(first_photon_emit_time, timer);
×
140
}
×
141

142
void RuleEngine::sendEmitPhotonSignalToQnic(QNIC_type qnic_type, int qnic_index, int qubit_index, bool is_first, bool is_last) {
6✔
143
  int pulse = 0;
6✔
144
  if (is_first) pulse |= STATIONARYQUBIT_PULSE_BEGIN;
6✔
145
  if (is_last) pulse |= STATIONARYQUBIT_PULSE_END;
6✔
146
  realtime_controller->EmitPhoton(qnic_index, qubit_index, qnic_type, pulse);
6✔
147
  emitted_photon_order_map[{qnic_type, qnic_index}].push_back(qubit_index);
6✔
148
}
6✔
149

150
simtime_t RuleEngine::getEmitTimeFromBSMNotification(quisp::messages::BSMTimingNotification *notification) { return notification->getFirstPhotonEmitTime(); }
×
151

152
void RuleEngine::stopOnGoingPhotonEmission(QNIC_type type, int qnic_index) { cancelEvent(emit_photon_timer_map[{type, qnic_index}]); }
×
153

154
void RuleEngine::freeFailedEntanglementAttemptQubits(QNIC_type type, int qnic_index) {
×
155
  auto &emitted_indices = emitted_photon_order_map[{type, qnic_index}];
×
156
  for (auto qubit_index : emitted_indices) {
×
157
    realtime_controller->ReInitialize_StationaryQubit(qnic_index, qubit_index, type, false);
×
158
    qnic_store->setQubitBusy(type, qnic_index, qubit_index, false);
×
159
  }
×
160
  emitted_indices.clear();
×
161
}
×
162

163
void RuleEngine::handleLinkGenerationResult(CombinedBSAresults *bsa_result) {
×
164
  auto type = bsa_result->getQnicType();
×
165
  auto qnic_index = bsa_result->getQnicIndex();
×
166
  auto num_success = bsa_result->getSuccessCount();
×
167
  auto partner_address = bsa_result->getNeighborAddress();
×
168
  auto &emitted_indices = emitted_photon_order_map[{type, qnic_index}];
×
169
  for (int i = num_success - 1; i >= 0; i--) {
×
170
    auto emitted_index = bsa_result->getSuccessfulPhotonIndices(i);
×
171
    auto qubit_index = emitted_indices[emitted_index];
×
172
    auto *qubit_record = qnic_store->getQubitRecord(type, qnic_index, qubit_index);
×
173
    auto iterator = emitted_indices.begin();
×
174
    std::advance(iterator, emitted_index);
×
175
    bell_pair_store.insertEntangledQubit(partner_address, qubit_record);
×
176
    emitted_indices.erase(iterator);
×
177

178
    auto correction_operation = bsa_result->getCorrectionOperationList(i);
×
179
    if (correction_operation == PauliOperator::X) {
×
180
      realtime_controller->applyXGate(qubit_record);
×
181
    } else if (correction_operation == PauliOperator::Y) {
×
182
      realtime_controller->applyXGate(qubit_record);
×
183
      realtime_controller->applyZGate(qubit_record);
×
184
    }
×
185
  }
×
186
}
×
187

188
void RuleEngine::handlePurificationResult(PurificationResult *result) {
×
189
  auto ruleset_id = result->getRulesetId();
×
190
  auto shared_rule_tag = result->getSharedRuleTag();
×
191
  auto sequence_number = result->getSequenceNumber();
×
192
  auto measurement_result = result->getMeasurementResult();
×
193
  auto purification_protocol = result->getProtocol();
×
194
  std::vector<int> message_content = {sequence_number, measurement_result, purification_protocol};
×
195
  auto runtime = runtimes.findById(ruleset_id);
×
196
  if (runtime == nullptr) return;
×
197
  runtime->assignMessageToRuleSet(shared_rule_tag, message_content);
×
198
}
×
199

200
void RuleEngine::handleSwappingResult(SwappingResult *result) {
×
201
  auto ruleset_id = result->getRulesetId();
×
202
  auto shared_rule_tag = result->getSharedRuleTag();
×
203
  auto sequence_number = result->getSequenceNumber();
×
204
  auto correction_frame = result->getCorrectionFrame();
×
205
  auto new_partner_addr = result->getNewPartner();
×
206
  std::vector<int> message_content = {sequence_number, correction_frame, new_partner_addr};
×
207
  auto runtime = runtimes.findById(ruleset_id);
×
208
  if (runtime == nullptr) return;
×
209
  runtime->assignMessageToRuleSet(shared_rule_tag, message_content);
×
210
}
×
211

212
// Invoked whenever a new resource (entangled with neighbor) has been created.
213
// Allocates those resources to a particular ruleset, from top to bottom (all of it).
214
void RuleEngine::ResourceAllocation(int qnic_type, int qnic_index) {
1✔
215
  for (auto &runtime : runtimes) {
1✔
216
    auto &partners = runtime.partners;
1✔
217
    for (auto &partner_addr : partners) {
1✔
218
      auto range = bell_pair_store.getBellPairsRange((QNIC_type)qnic_type, qnic_index, partner_addr.val);
1✔
219
      for (auto it = range.first; it != range.second; ++it) {
2✔
220
        auto qubit_record = it->second;
1✔
221

222
        // 3. if the qubit is not allocated yet, and the qubit has not been allocated to this rule,
223
        // if the qubit has already been assigned to the rule, the qubit is not allocatable to that rule
224
        if (!qubit_record->isAllocated()) {  //&& !qubit_record->isRuleApplied((*rule)->rule_id
1✔
225
          qubit_record->setAllocated(true);
1✔
226
          runtime.assignQubitToRuleSet(partner_addr, qubit_record);
1✔
227
        }
1✔
228
      }
1✔
229
    }
1✔
230
  }
1✔
231
}
1✔
232

233
void RuleEngine::executeAllRuleSets() { runtimes.exec(); }
7✔
234

235
void RuleEngine::freeConsumedResource(int qnic_index /*Not the address!!!*/, IStationaryQubit *qubit, QNIC_type qnic_type) {
1✔
236
  auto *qubit_record = qnic_store->getQubitRecord(qnic_type, qnic_index, qubit->par("stationary_qubit_address"));
1✔
237
  realtime_controller->ReInitialize_StationaryQubit(qubit_record, false);
1✔
238
  qubit_record->setBusy(false);
1✔
239
  if (qubit_record->isAllocated()) {
1✔
240
    qubit_record->setAllocated(false);
×
241
  }
×
242
  bell_pair_store.eraseQubit(qubit_record);
1✔
243
}
1✔
244

245
}  // namespace quisp::modules
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