LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
map2renv.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_IO_MAP2RENV_H
6#define LINE_IO_MAP2RENV_H
7
8/**
9 * @file
10 * @ingroup line_io
11 * Port of matlab/src/io/map2renv.m and matlab/src/io/MAPQN2RENV.m (python twin
12 * in api/io/converters.py): the Markov-modulated image of a network with
13 * MAP/MMPP/MMAP arrival or service processes as a queueing network in a
14 * random environment.
15 *
16 * Every non-renewal process is a point process modulated by the CTMC with
17 * generator Q = D0 + D1, whose conditional intensity in phase k is
18 * lambda(k) = sum_j D1(k,j). The transformation freezes each phase into an
19 * environment stage in which the process is the Poisson process of that
20 * intensity, and lets the environment switch stages at the rates of Q. With P
21 * modulated processes the stage set is the Cartesian product of their phase
22 * spaces and the environment generator is the Kronecker sum of the individual
23 * Q's, so only one process changes phase at a time. The image is exact in
24 * structure for an MMPP (diagonal D1); for a general MAP the phase jumps AT an
25 * event epoch are aggregated into Q and their correlation with the event
26 * stream is lost. Populations are carried across stage switches unchanged
27 * (identity reset), as a phase switch moves no job.
28 *
29 * ARITHMETIC: field, through `sn_map_modulation` and the struct refresh.
30 */
31
32#include <cstddef>
33#include <string>
34#include <vector>
35
40#include "line/num/number.h"
41#include "line/util/error.h"
42
43namespace line {
44namespace io {
45
46/** The INFO output of map2renv: how the stage set was assembled. */
47template <class T>
49 std::size_t nstages = 0;
50 /** Phase order of each modulated process. */
51 std::vector<std::size_t> orders;
52 /** True when every process was an MMPP, so the image is exact in structure. */
53 bool is_mmpp = true;
54 /** The modulation records themselves. */
55 std::vector<api::SnMapModulation<T>> mods;
56};
57
58/**
59 * @param base the network, as its NetworkStruct
60 * @param info optional INFO output
61 * @param max_stages cap on the environment stage count, the reference's
62 * options.config.map_env_maxstages (default 64)
63 */
64template <class T>
66 std::size_t max_stages = 64) {
67 const double zero_tol = lang::GlobalConstants::Zero;
68 const std::vector<api::SnMapModulation<T>> mods = api::sn_map_modulation(base);
69 if (mods.empty())
70 throw InputError(
71 "map2renv: the model declares no MAP, MMPP2 or MMAP process, so it has no "
72 "random-environment image");
73
74 const std::size_t P = mods.size();
75 std::vector<std::size_t> orders(P);
76 std::size_t nstages = 1;
77 for (std::size_t p = 0; p < P; ++p) {
78 orders[p] = mods[p].order;
79 nstages *= orders[p];
80 }
81 if (nstages > max_stages)
82 throw InputError("map2renv: the random-environment image of this model has " +
83 std::to_string(nstages) +
84 " stages, above the max_stages cap of " + std::to_string(max_stages) +
85 "; reduce the order of the modulating processes or raise the cap");
86
87 // stage s enumerates the phase tuples in column-major order, 0-based
88 std::vector<std::vector<std::size_t>> phase_of(nstages, std::vector<std::size_t>(P, 0));
89 for (std::size_t s = 0; s < nstages; ++s) {
90 std::size_t rem = s;
91 for (std::size_t p = 0; p < P; ++p) {
92 phase_of[s][p] = rem % orders[p];
93 rem /= orders[p];
94 }
95 }
96
97 env::Environment<T> envModel(base.name + "_renv", nstages);
98 for (std::size_t s = 0; s < nstages; ++s) {
99 std::string nm = "Phase";
100 for (std::size_t p = 0; p < P; ++p) nm += "_" + std::to_string(phase_of[s][p] + 1);
101
102 // copy of the base model in which every modulated process is the
103 // exponential process of its phase-conditional intensity
104 qn::NetworkStruct<T> stage = base;
105 stage.name = base.name + "_" + nm;
106 for (std::size_t p = 0; p < P; ++p) {
107 for (std::size_t c = 0; c < mods[p].classes.size(); ++c) {
108 const std::size_t r = mods[p].classes[c];
109 const Matrix<T>& D1 = mods[p].D1[c];
110 T rate = num_traits<T>::from_int(0);
111 for (std::size_t j = 0; j < D1.cols(); ++j) rate += D1(phase_of[s][p], j);
112 if (mods[p].arrival) {
113 // a silent phase (zero intensity) stays an ON/OFF source:
114 // the class must exist in every stage so the rate-averaged
115 // limit averages a zero instead of skipping the station
116 if (!(num_traits<T>::to_double(rate) > zero_tol))
117 rate = num_traits<T>::from_double(zero_tol);
118 stage.set_service(mods[p].ist, r, lang::Distrib<T>::exp_rate(rate));
119 } else {
120 if (!(num_traits<T>::to_double(rate) > zero_tol))
121 throw InputError(
122 "map2renv: phase " + std::to_string(phase_of[s][p] + 1) +
123 " of the service process of class " + std::to_string(r) +
124 " at station " + std::to_string(mods[p].ist) +
125 " has zero completion rate: the station never empties while the "
126 "environment sits in that stage, so the stage has no steady state "
127 "and the random-environment image is not defined; model the "
128 "stalled server as a breakdown stage instead");
129 stage.set_service(mods[p].ist, r, lang::Distrib<T>::exp_rate(rate));
130 }
131 }
132 // THE MARK BINDING DOES NOT SURVIVE THE FREEZE. Every mark became
133 // its own Exp stream above, so a stage that still advertised
134 // `marked_classes` would claim a marked arrival it no longer has --
135 // and `markidx_of` is derived from that vector, so `phasessz` would
136 // keep collapsing the non-carrier marks to one phase. Benign today
137 // because every marked branch tests `procid` first, and a trap
138 // exactly for that reason.
139 if (mods[p].arrival && mods[p].ist >= 1 && mods[p].ist <= stage.stations.size())
140 stage.stations[mods[p].ist - 1].marked_classes.clear();
141 }
142 stage.refresh_struct();
143 envModel.set_stage(s, nm, "item", stage);
144 }
145
146 // Kronecker sum of the phase generators: a transition changes the phase of
147 // one process only, at the rate that process assigns to it
148 for (std::size_t s = 0; s < nstages; ++s) {
149 std::size_t stride = 1;
150 for (std::size_t p = 0; p < P; ++p) {
151 Matrix<T> Qp = mods[p].D0;
152 for (const Matrix<T>& D1 : mods[p].D1)
153 for (std::size_t a = 0; a < Qp.rows(); ++a)
154 for (std::size_t b = 0; b < Qp.cols(); ++b) Qp(a, b) += D1(a, b);
155 const std::size_t k = phase_of[s][p];
156 for (std::size_t l = 0; l < orders[p]; ++l) {
157 if (l == k) continue;
158 const double q = num_traits<T>::to_double(Qp(k, l));
159 if (q > zero_tol) {
160 const std::size_t t = static_cast<std::size_t>(
161 static_cast<std::ptrdiff_t>(s) +
162 (static_cast<std::ptrdiff_t>(l) - static_cast<std::ptrdiff_t>(k)) *
163 static_cast<std::ptrdiff_t>(stride));
164 envModel.add_transition(s, t, lang::Distrib<T>::exp_rate(Qp(k, l)));
165 }
166 }
167 stride *= orders[p];
168 }
169 }
170
171 envModel.init();
172
173 if (info != nullptr) {
174 info->nstages = nstages;
175 info->orders = orders;
176 info->is_mmpp = true;
177 for (const api::SnMapModulation<T>& m : mods)
178 if (!m.is_mmpp) info->is_mmpp = false;
179 info->mods = mods;
180 }
181 return envModel;
182}
183
184/**
185 * Retained name for the transformation now implemented by `map2renv`, which
186 * generalizes it from a single MMPP2 service process to any number of MAP,
187 * MMPP2 or MMAP processes of arbitrary phase order. New code should call
188 * `map2renv` directly.
189 */
190template <class T>
192 Map2RenvInfo<T>* info = nullptr, std::size_t max_stages = 64) {
193 return map2renv(base, info, max_stages);
194}
195
196} // namespace io
197} // namespace line
198
199#endif // LINE_IO_MAP2RENV_H
InputError(const std::string &what)
Definition error.h:39
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
void init()
Port of Environment.init().
void set_stage(std::size_t e, const std::string &nm, const std::string &type, const qn::NetworkStruct< T > &model)
addStage: name the stage and give it its network.
void add_transition(std::size_t e, std::size_t h, const lang::Distrib< T > &d, const ResetMarginal &reset=ResetMarginal())
addTransition: enable e -> h with a distribution and a reset policy.
A network plus its refreshed NetworkStruct.
std::vector< Station< T > > stations
stations[k-1] is the k-th station
void refresh_struct()
The whole chain, in MATLAB's refreshStruct order.
void set_service(std::size_t station, std::size_t cls, const Distrib< T > &d)
A random environment: a port of matlab/src/lang/Environment.m, restricted to what SolverENV reads out...
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
std::vector< SnMapModulation< T > > sn_map_modulation(const qn::NetworkStruct< T > &sn)
env::Environment< T > map2renv(const qn::NetworkStruct< T > &base, Map2RenvInfo< T > *info=nullptr, std::size_t max_stages=64)
Definition map2renv.h:65
env::Environment< T > mapqn2renv(const qn::NetworkStruct< T > &base, Map2RenvInfo< T > *info=nullptr, std::size_t max_stages=64)
Retained name for the transformation now implemented by map2renv, which generalizes it from a single ...
Definition map2renv.h:191
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
Port of matlab/src/api/sn/sn_map_modulation.m.
One modulating process: which station and classes it drives, and its blocks.
The INFO output of map2renv: how the stage set was assembled.
Definition map2renv.h:48
bool is_mmpp
True when every process was an MMPP, so the image is exact in structure.
Definition map2renv.h:53
std::vector< api::SnMapModulation< T > > mods
The modulation records themselves.
Definition map2renv.h:55
std::size_t nstages
Definition map2renv.h:49
std::vector< std::size_t > orders
Phase order of each modulated process.
Definition map2renv.h:51
static Distrib exp_rate(const T &r)
Definition lang_types.h:945
static constexpr double Zero
Definition lang_types.h:762