14#include "ns3/q2ns-qmap.h"
16#include "ns3/q2ns-qgate.h"
17#include "ns3/q2ns-qnode.h"
18#include "ns3/q2ns-qubit.h"
20#include "ns3/attribute.h"
21#include "ns3/double.h"
22#include "ns3/integer.h"
24#include "ns3/string.h"
31NS_LOG_COMPONENT_DEFINE(
"QMap");
33NS_OBJECT_ENSURE_REGISTERED(QMap);
36 static ns3::TypeId tid =
37 ns3::TypeId(
"q2ns::QMap")
38 .SetParent<ns3::Object>()
40 .AddAttribute(
"Probability",
41 "Base application probability used when Rate is 0. "
42 "If Rate > 0, Probability is ignored.",
43 ns3::DoubleValue(0.0), ns3::MakeDoubleAccessor(&
QMap::p_),
44 ns3::MakeDoubleChecker<double>(0.0, 1.0))
46 "QMap event rate in 1/s. If > 0, the per-flight "
47 "application probability is p(t)=1-exp(-Rate*elapsedTime).",
48 ns3::DoubleValue(0.0), ns3::MakeDoubleAccessor(&
QMap::rate_),
49 ns3::MakeDoubleChecker<double>(0.0));
72 static ns3::TypeId tid = ns3::TypeId(
"q2ns::CompositeQMap")
83 void SetMaps(
const std::vector<ns3::Ptr<QMap>>& maps) {
91 std::vector<QMapInstance> inst;
92 inst.reserve(maps_.size());
93 for (
const auto& m : maps_) {
97 return [inst = std::move(inst)](
QNode& node, std::shared_ptr<Qubit>& q)
mutable {
98 for (
auto& f : inst) {
104 auto loc = q->GetLocation();
105 if (loc.type == LocationType::Lost) {
122ns3::Ptr<QMap>
QMap::Compose(
const ns3::Ptr<QMap>& a,
const ns3::Ptr<QMap>& b) {
123 std::vector<ns3::Ptr<QMap>> v;
133 auto out = ns3::CreateObject<CompositeQMap>();
141 return ns3::CreateObject<LambdaQMap>(std::move(f));
148 ns3::Ptr<ns3::UniformRandomVariable>,
const QMapContext&)>
150 return ns3::CreateObject<LambdaQMap>(std::move(f));
158 static ns3::TypeId tid = ns3::TypeId(
"q2ns::LambdaQMap")
160 .SetGroupName(
"q2ns")
195 return [adv, u, ctx](
QNode& node, std::shared_ptr<Qubit>& q)
mutable { adv(node, q, u, ctx); };
200 return [simp](
QNode& node, std::shared_ptr<Qubit>& q)
mutable { simp(node, q); };
211 static ns3::TypeId tid = ns3::TypeId(
"q2ns::ConditionalQMap")
213 .SetGroupName(
"q2ns")
227 cond_ = std::move(pred);
234 const auto pred =
cond_;
237 return [pred, ctx, qmapInst](
QNode& node, std::shared_ptr<Qubit>& q)
mutable {
241 if (!pred || pred(q, ctx)) {
252 static ns3::TypeId tid = ns3::TypeId(
"q2ns::DephasingQMap")
254 .SetGroupName(
"q2ns")
264 return [flip](
QNode& node, std::shared_ptr<Qubit>& q) {
276 static ns3::TypeId tid = ns3::TypeId(
"q2ns::DepolarizingQMap")
278 .SetGroupName(
"q2ns")
291 r = u->GetInteger(0, 2);
294 return [apply, r](
QNode& node, std::shared_ptr<Qubit>& q) {
310NS_OBJECT_ENSURE_REGISTERED(
LossQMap);
313 static ns3::TypeId tid = ns3::TypeId(
"q2ns::LossQMap")
315 .SetGroupName(
"q2ns")
325 return [lose](
QNode&, std::shared_ptr<Qubit>& q) {
337 static ns3::TypeId tid = ns3::TypeId(
"q2ns::RandomGateQMap")
339 .SetGroupName(
"q2ns")
355 NS_ABORT_MSG_IF(weight < 0.0, "RandomGateQMap: weight must be >= 0
");
356 gates_.push_back(gate);
357 weights_.push_back(weight);
358 totalWeight_ += weight;
363void RandomGateQMap::SetDistribution(std::vector<QGate> gates, std::vector<double> weights) {
364 NS_ABORT_MSG_IF(gates.size() != weights.size(),
367 gates_ = std::move(gates);
368 weights_ = std::move(weights);
371 for (double w : weights_) {
379std::size_t RandomGateQMap::PickIndex_(ns3::Ptr<ns3::UniformRandomVariable> u) const {
380 NS_ABORT_MSG_IF(gates_.empty(), "RandomGateQMap: no gates configured
");
381 NS_ABORT_MSG_IF(totalWeight_ <= 0.0, "RandomGateQMap: total weight must be > 0
");
383 const double r = u->GetValue(0.0, totalWeight_);
385 for (std::size_t i = 0; i < weights_.size(); ++i) {
391 return weights_.size() - 1;
396QMapInstance RandomGateQMap::Sample(ns3::Ptr<ns3::UniformRandomVariable> u,
397 const QMapContext& ctx) const {
398 const bool apply = Bernoulli_(u, ctx);
407 return [apply, gate = std::move(gate)](QNode& node, std::shared_ptr<Qubit>& q) mutable {
409 node.Apply(gate, {q});
416NS_OBJECT_ENSURE_REGISTERED(RandomUnitaryQMap);
418ns3::TypeId RandomUnitaryQMap::GetTypeId() {
421 .SetGroupName("q2ns")
422 .AddConstructor<RandomUnitaryQMap>();
428// Haar-random SU(2) from a random unit quaternion on S^3.
429// Converted to the 2x2 unitary
430// [ u0 + i u3 u2 + i u1 ]
431// [ -u2 + i u1 u0 - i u3 ].
432Matrix RandomUnitaryQMap::SampleHaarSU2_(ns3::Ptr<ns3::UniformRandomVariable> u) {
433 const double a = u->GetValue(0.0, 1.0);
434 const double b = u->GetValue(0.0, 1.0);
435 const double c = u->GetValue(0.0, 1.0);
437 const double s1 = std::sqrt(1.0 - a);
438 const double s2 = std::sqrt(a);
439 constexpr double kTwoPi = 6.28318530717958647692;
440 const double t1 = kTwoPi * b;
441 const double t2 = kTwoPi * c;
443 const double u0 = s2 * std::cos(t2);
444 const double u3 = s2 * std::sin(t2);
445 const double u2 = s1 * std::cos(t1);
446 const double u1 = s1 * std::sin(t1);
448 const Complex A(u0, u3);
449 const Complex B(u2, u1);
450 const Complex C(-u2, u1);
451 const Complex D(u0, -u3);
453 return MakeMatrix({{A, B}, {C, D}});
458QMapInstance RandomUnitaryQMap::Sample(ns3::Ptr<ns3::UniformRandomVariable> u,
459 const QMapContext& ctx) const {
460 const bool apply = Bernoulli_(u, ctx);
464 U = SampleHaarSU2_(u);
467 return [apply, U = std::move(U)](QNode& node, std::shared_ptr<Qubit>& q) mutable {
QMap wrapper that conditionally applies another QMap.
void SetQMap(ns3::Ptr< QMap > qmap)
Set the wrapped QMap.
QMapInstance Sample(ns3::Ptr< ns3::UniformRandomVariable > u, const QMapContext &ctx=QMapContext{}) const override
Sample a per-transmission QMapInstance.
Condition cond_
Application predicate.
std::function< bool(const std::shared_ptr< Qubit > &, const QMapContext &)> Condition
Predicate type controlling whether the wrapped map is applied.
void SetCondition(Condition pred)
Set the condition predicate.
static ns3::TypeId GetTypeId()
Get the ns-3 TypeId.
ns3::Ptr< QMap > qmap_
Wrapped QMap.
Dephasing noise model that applies Z with probability p.
static ns3::TypeId GetTypeId()
Get the ns-3 TypeId.
QMapInstance Sample(ns3::Ptr< ns3::UniformRandomVariable > u, const QMapContext &ctx=QMapContext{}) const override
Sample a per-transmission QMapInstance.
Trajectory-style depolarizing model that applies a random Pauli from {X, Y, Z} with probability p.
static ns3::TypeId GetTypeId()
Get the ns-3 TypeId.
QMapInstance Sample(ns3::Ptr< ns3::UniformRandomVariable > u, const QMapContext &ctx=QMapContext{}) const override
Sample a per-transmission QMapInstance.
QMap implementation that wraps a user-provided lambda.
AdvancedFn advanced_
Advanced callable, if configured.
static ns3::TypeId GetTypeId()
Get the ns-3 TypeId.
void Set(SimpleFn f)
Replace the stored callable with a simple callable.
QMapInstance Sample(ns3::Ptr< ns3::UniformRandomVariable > u, const QMapContext &ctx=QMapContext{}) const override
Sample a per-transmission QMapInstance.
std::function< void(QNode &, std::shared_ptr< Qubit > &, ns3::Ptr< ns3::UniformRandomVariable >, const QMapContext &)> AdvancedFn
Advanced callable type.
LambdaQMap()=default
Default constructor.
std::function< void(QNode &, std::shared_ptr< Qubit > &)> SimpleFn
Simple callable type.
SimpleFn simple_
Simple callable, if configured.
Erasure model that marks the qubit lost with probability p.
QMapInstance Sample(ns3::Ptr< ns3::UniformRandomVariable > u, const QMapContext &ctx=QMapContext{}) const override
Sample a per-transmission QMapInstance.
static ns3::TypeId GetTypeId()
Get the ns-3 TypeId.
Lightweight gate descriptor used by QState backends.
Abstract base class for channel map models.
static ns3::Ptr< QMap > Compose(const ns3::Ptr< QMap > &a, const ns3::Ptr< QMap > &b)
Compose two QMaps into one sequential composite QMap.
static void SetLost_(Qubit &q)
Mark a qubit lost through the standard registry-backed location path.
static ns3::Ptr< QMap > FromLambda(std::function< void(QNode &, std::shared_ptr< Qubit > &)> f)
Build a QMap from a simple lambda.
double p_
Direct per-transmission probability.
double rate_
Poisson event rate in 1/s. Overrides p_ when positive.
static ns3::TypeId GetTypeId()
Get the ns-3 TypeId.
bool Bernoulli_(ns3::Ptr< ns3::UniformRandomVariable > u, const QMapContext &ctx) const
Perform one Bernoulli trial using the effective probability.
Main user-facing per-node API for quantum operations and transmission.
bool Apply(const QGate &gate, const std::vector< std::shared_ptr< Qubit > > &qs)
Apply a gate to one or more local qubits.
Lightweight handle for one qubit inside a registry-managed state.
void SetLocationLost()
Mark this qubit as lost.
QMap that samples one gate from a weighted distribution and applies it.
static ns3::TypeId GetTypeId()
Get the ns-3 TypeId.
void AddGate(const QGate &gate, double weight)
Append one weighted gate to the distribution.
double totalWeight_
Sum of all selection weights.
void Clear()
Clear the weighted gate distribution.
std::vector< QGate > gates_
Candidate gates.
std::vector< double > weights_
Selection weights.
QMap that applies one Haar-random single-qubit SU(2) unitary.
Internal QMap implementation for sequential composition.
QMapInstance Sample(ns3::Ptr< ns3::UniformRandomVariable > u, const QMapContext &ctx=QMapContext{}) const override
Sample a per-transmission QMapInstance.
static ns3::TypeId GetTypeId()
void SetMaps(const std::vector< ns3::Ptr< QMap > > &maps)
std::vector< ns3::Ptr< QMap > > maps_
Component maps in left-to-right order.
std::function< void(QNode &, std::shared_ptr< Qubit > &)> QMapInstance
Per-transmission quantum map callable applied to a received qubit.
QGate Y(ns3::Time d=ns3::Seconds(0))
Return the Pauli-Y gate descriptor.
QGate X(ns3::Time d=ns3::Seconds(0))
Return the Pauli-X gate descriptor.
QGate Z(ns3::Time d=ns3::Seconds(0))
Return the Pauli-Z gate descriptor.
Optional per-sample context passed to QMaps.