Q2NS dev
ns-3 module
Loading...
Searching...
No Matches
q2ns-netcontroller.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-netcontroller.cc
11 * @brief Defines q2ns::NetController.
12 */
13
14#include "ns3/q2ns-netcontroller.h"
15
16#include "ns3/q2ns-qchannel.h"
17#include "ns3/q2ns-qmap.h"
18#include "ns3/q2ns-qnet-device.h"
19#include "ns3/q2ns-qnode.h"
20#include "ns3/q2ns-qstate.h"
21#include "ns3/q2ns-qubit.h"
22#include "q2ns-qnetworker.h"
23
24#include "ns3/log.h"
25#include "ns3/names.h"
26#include "ns3/node.h"
27#include "ns3/rng-seed-manager.h"
28#include "ns3/simulator.h"
29
30#include <algorithm>
31#include <string>
32#include <utility>
33
34namespace q2ns {
35
36NS_LOG_COMPONENT_DEFINE("NetController");
37
39 // Schedule a one-time initializer at time 0 so RNG stream binding uses the
40 // final ns-3 seed/run settings regardless of whether the user calls a
41 // controller helper or ns3::Simulator::Run() directly.
42 ns3::Simulator::ScheduleNow(&NetController::EnsureStreamsAssigned_, this);
43
44 // Install a registry hook so states created after stream assignment receive
45 // deterministic streams automatically.
47 if (!streamsAssigned_) {
48 return;
49 }
51 });
52}
53
54int64_t NetController::AssignStreams(int64_t stream) {
55 if (streamsAssigned_) {
56 NS_LOG_WARN("AssignStreams called more than once; streams will be reassigned.");
57 }
58
59 streamsAssigned_ = true;
60 nextStream_ = stream;
61
62 int64_t used = 0;
63
64 // Channels are stored in std::map, so iteration order is deterministic.
65 for (auto& kv : channels_) {
66 auto& ch = kv.second;
67 const int64_t n = ch->AssignStreams(nextStream_);
68 nextStream_ += n;
69 used += n;
70 }
71
72 // States are stored internally in an unordered container, so assign streams
73 // in sorted state-id order for deterministic behavior.
74 for (auto& st : registry_.GetStatesSortedById()) {
75 if (st) {
76 const int64_t n = st->AssignStreams(nextStream_);
77 nextStream_ += n;
78 used += n;
79 }
80 }
81
82 return used;
83}
84
86 if (streamsAssigned_) {
87 return;
88 }
89
91}
92
96
100
104
108
109ns3::Ptr<QNode> NetController::CreateNode(const std::string& label) {
110 auto qnode = ns3::CreateObject<QNode>(registry_);
111
112 const uint32_t id = qnode->GetId();
113 nodes_[id] = qnode;
114
115 if (!label.empty()) {
116 ns3::Names::Add(label, qnode);
117 }
118
119 return qnode;
120}
121
122ns3::Ptr<QNode> NetController::GetNode(uint32_t nodeId) {
123 auto it = nodes_.find(nodeId);
124 if (it != nodes_.end() && it->second) {
125 return it->second;
126 }
127
128 return nullptr;
129}
130
131ns3::Ptr<QChannel> NetController::InstallQuantumLink(ns3::Ptr<QNode> a, ns3::Ptr<QNode> b) {
132 if (!a || !b) {
133 NS_LOG_WARN("InstallQuantumLink rejected: null node.");
134 return nullptr;
135 }
136
137 const uint32_t ida = a->GetId();
138 const uint32_t idb = b->GetId();
139 const auto key = std::make_pair(std::min(ida, idb), std::max(ida, idb));
140
141 auto it = channels_.find(key);
142 if (it != channels_.end()) {
143 NS_LOG_WARN("InstallQuantumLink reused existing channel for nodes " << ida << " and " << idb
144 << ".");
145 return it->second;
146 }
147
148 auto devA = ns3::CreateObject<QNetDevice>();
149 auto devB = ns3::CreateObject<QNetDevice>();
150 auto chan = ns3::CreateObject<QChannel>();
151
152 if (streamsAssigned_) {
153 nextStream_ += chan->AssignStreams(nextStream_);
154 }
155
156 chan->Connect(devA, devB);
157
158 a->AddDevice(devA);
159 b->AddDevice(devB);
160
161 const uint32_t ifA = a->networker_->AddInterface(devA);
162 const uint32_t ifB = b->networker_->AddInterface(devB);
163
164 a->networker_->AddRoute(idb, ifA);
165 b->networker_->AddRoute(ida, ifB);
166
167 channels_[key] = chan;
168 return chan;
169}
170
171std::vector<ns3::Ptr<QChannel>>
172NetController::InstallQuantumChain(const std::vector<ns3::Ptr<QNode>>& nodes) {
173 std::vector<ns3::Ptr<QChannel>> channels;
174 if (nodes.size() < 2) {
175 return channels;
176 }
177
178 channels.reserve(nodes.size() - 1);
179
180 for (std::size_t i = 0; i + 1 < nodes.size(); ++i) {
181 const auto& a = nodes[i];
182 const auto& b = nodes[i + 1];
183
184 if (!a || !b) {
185 NS_LOG_WARN("InstallQuantumChain skipped link at positions " << i << " and " << (i + 1)
186 << " because a node was null.");
187 continue;
188 }
189
190 if (a == b) {
191 NS_LOG_WARN("InstallQuantumChain skipped self-link at positions " << i << " and " << (i + 1)
192 << ".");
193 continue;
194 }
195
196 channels.push_back(InstallQuantumLink(a, b));
197 }
198
199 return channels;
200}
201
202std::vector<ns3::Ptr<QChannel>>
203NetController::InstallQuantumAllToAll(const std::vector<ns3::Ptr<QNode>>& nodes) {
204 std::vector<ns3::Ptr<QChannel>> channels;
205 if (nodes.size() < 2) {
206 return channels;
207 }
208
209 const std::size_t n = nodes.size();
210 channels.reserve((n * (n - 1)) / 2);
211
212 for (std::size_t i = 0; i < n; ++i) {
213 const auto& a = nodes[i];
214 if (!a) {
215 NS_LOG_WARN("InstallQuantumAllToAll skipped all pairs involving null node at position "
216 << i << ".");
217 continue;
218 }
219
220 for (std::size_t j = i + 1; j < n; ++j) {
221 const auto& b = nodes[j];
222
223 if (!b) {
224 NS_LOG_WARN("InstallQuantumAllToAll skipped pair at positions "
225 << i << " and " << j << " because a node was null.");
226 continue;
227 }
228
229 if (a == b) {
230 NS_LOG_WARN("InstallQuantumAllToAll skipped self-link at positions " << i << " and " << j
231 << ".");
232 continue;
233 }
234
235 channels.push_back(InstallQuantumLink(a, b));
236 }
237 }
238
239 return channels;
240}
241
242ns3::Ptr<QChannel> NetController::GetChannel(ns3::Ptr<QNode> a, ns3::Ptr<QNode> b) {
243 if (!a || !b) {
244 NS_LOG_WARN("GetChannel rejected: null node.");
245 return nullptr;
246 }
247
248 const uint32_t ida = a->GetId();
249 const uint32_t idb = b->GetId();
250 const auto key = std::make_pair(std::min(ida, idb), std::max(ida, idb));
251
252 auto it = channels_.find(key);
253 if (it == channels_.end()) {
254 NS_LOG_WARN("GetChannel failed: no channel connects the provided nodes.");
255 return nullptr;
256 }
257
258 return it->second;
259}
260
261std::shared_ptr<QState> NetController::GetState(const std::shared_ptr<Qubit>& q) const {
262 return registry_.GetState(q);
263}
264
265} // namespace q2ns
std::map< std::pair< uint32_t, uint32_t >, ns3::Ptr< QChannel > > channels_
Undirected link map keyed by sorted endpoint ids.
QStateRegistry registry_
Shared state registry.
QStateRegistry & GetRegistry()
Access the shared state registry.
void EnsureStreamsAssigned_()
Ensure RNG streams have been assigned before simulation activity begins.
int64_t nextStream_
Next stream index to assign.
ns3::Ptr< QChannel > GetChannel(ns3::Ptr< QNode > a, ns3::Ptr< QNode > b)
Return the QChannel connecting two nodes.
int64_t AssignStreams(int64_t stream)
Assign RNG streams to q2ns-owned random sources.
std::vector< ns3::Ptr< QChannel > > InstallQuantumAllToAll(const std::vector< ns3::Ptr< QNode > > &nodes)
Connect a set of nodes with all-to-all quantum links.
QStateBackend GetQStateBackend()
Get the current default backend.
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 > GetNode(uint32_t nodeId)
Return the QNode associated with a node id.
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.
bool streamsAssigned_
True once AssignStreams has been called.
NetController()
Default constructor.
std::unordered_map< uint32_t, ns3::Ptr< QNode > > nodes_
Node id to QNode map.
std::vector< ns3::Ptr< QChannel > > InstallQuantumChain(const std::vector< ns3::Ptr< QNode > > &nodes)
Connect a sequence of nodes as a linear chain.
void SetQStateBackend(QStateBackend b)
Set the default backend used for newly created quantum states.
Internal registry that owns backend states and tracks qubit membership and location.
QStateBackend GetDefaultBackend() const
Get the default backend used for newly created states.
void SetDefaultBackend(QStateBackend b)
Set the default backend used for newly created states.
std::vector< std::shared_ptr< QState > > GetStatesSortedById() const
Return all registered states sorted by state id.
std::shared_ptr< QState > GetState(StateId stateId) const
Get a backend state by state id.
void SetStreamAssigner(StreamAssigner fn)
Set the callback used to assign streams to newly created states.
Backend-agnostic interface for a quantum state object.
Definition q2ns-qstate.h:51
virtual int64_t AssignStreams(int64_t stream)
Assign RNG streams for deterministic randomness.
Definition q2ns-qstate.h:70
QStateBackend BackendFromString(std::string_view s)
Convert a backend name string to a QStateBackend enum value.
QStateBackend
Backend family used when creating new quantum states.
Definition q2ns-types.h:94
Declares q2ns::QNetworker, an internal per-node networking component for quantum transmission and rec...