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 }
133 stage.refresh_struct();
134 envModel.set_stage(s, nm, "item", stage);
135 }
136
137 // Kronecker sum of the phase generators: a transition changes the phase of
138 // one process only, at the rate that process assigns to it
139 for (std::size_t s = 0; s < nstages; ++s) {
140 std::size_t stride = 1;
141 for (std::size_t p = 0; p < P; ++p) {
142 Matrix<T> Qp = mods[p].D0;
143 for (const Matrix<T>& D1 : mods[p].D1)
144 for (std::size_t a = 0; a < Qp.rows(); ++a)
145 for (std::size_t b = 0; b < Qp.cols(); ++b) Qp(a, b) += D1(a, b);
146 const std::size_t k = phase_of[s][p];
147 for (std::size_t l = 0; l < orders[p]; ++l) {
148 if (l == k) continue;
149 const double q = num_traits<T>::to_double(Qp(k, l));
150 if (q > zero_tol) {
151 const std::size_t t = static_cast<std::size_t>(
152 static_cast<std::ptrdiff_t>(s) +
153 (static_cast<std::ptrdiff_t>(l) - static_cast<std::ptrdiff_t>(k)) *
154 static_cast<std::ptrdiff_t>(stride));
155 envModel.add_transition(s, t, lang::Distrib<T>::exp_rate(Qp(k, l)));
156 }
157 }
158 stride *= orders[p];
159 }
160 }
161
162 envModel.init();
163
164 if (info != nullptr) {
165 info->nstages = nstages;
166 info->orders = orders;
167 info->is_mmpp = true;
168 for (const api::SnMapModulation<T>& m : mods)
169 if (!m.is_mmpp) info->is_mmpp = false;
170 info->mods = mods;
171 }
172 return envModel;
173}
174
175/**
176 * Retained name for the transformation now implemented by `map2renv`, which
177 * generalizes it from a single MMPP2 service process to any number of MAP,
178 * MMPP2 or MMAP processes of arbitrary phase order. New code should call
179 * `map2renv` directly.
180 */
181template <class T>
183 Map2RenvInfo<T>* info = nullptr, std::size_t max_stages = 64) {
184 return map2renv(base, info, max_stages);
185}
186
187} // namespace io
188} // namespace line
189
190#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.
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:182
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:814
static constexpr double Zero
Definition lang_types.h:670