LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
solver_ctmc_mapc.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_SOLVERS_CTMC_SOLVER_CTMC_MAPC_H
6#define LINE_SOLVERS_CTMC_SOLVER_CTMC_MAPC_H
7
8/**
9 * @file
10 * @ingroup line_solvers
11 * Port of `solver_ctmc_mapc.m`: the pair form of a MAP (and MMPP2) service at an FCFS
12 * station, so the CTMC follows the law JMT and both LDES engines sample.
13 *
14 * Those engines keep ONE sampler per (station, class): every draw starts in the phase the
15 * previous draw ENDED in, draws chained in service-start order, idle periods included. With
16 * c > 1 servers the next start can happen while earlier draws are still running, so the
17 * landing phase of a draw must be known when it starts. With V = (-D0)^-1 D1 a draw started
18 * in h ends in j w.p. V(h,j); a busy server is a PAIR (i,j) that moves i->k at
19 * D0(i,k)V(k,j)/V(i,j) and completes at D1(i,j)/V(i,j). The class memory variable is the
20 * landing of the most recently STARTED draw: a start from h enters (h,j) w.p. V(h,j) and sets
21 * h := j, while moves and completions keep it. For a renewal MAP the chain reduces in law to
22 * PH/c. The pair law is stored as the lifted MAP D0p (conditioned moves) and
23 * D1p((i,j),(j,j')) = D1(i,j)/V(i,j)*V(j,j'), equivalent in law to the original; the
24 * bookkeeping read by the state handlers goes to `sn.ctmcmapc`.
25 *
26 * As in the reference, only a multiserver station is rewritten. A single server keeps its law and
27 * gets a `single` entry: the memory is the phase the last completion left the MAP in, which the
28 * handlers here did not carry before, so every draw restarted from the entry law. Pairs at c = 1
29 * would be exact too but multiply the space, most of it unreachable, for no gain in the law.
30 */
31
32#include <cmath>
33#include <cstddef>
34#include <map>
35#include <utility>
36#include <vector>
37
41#include "line/util/error.h"
42#include "line/util/linalg.h"
43#include "line/util/matrix.h"
44
45namespace line {
46namespace ctmc {
47
48namespace mapc_detail {
49
50template <class T>
51bool wants_mapc(const qn::NetworkStruct<T>& sn, std::size_t ist, std::size_t r) {
52 const qn::Station<T>& st = sn.stations[ist - 1];
53 if (st.sched != lang::SchedStrategy::FCFS || !std::isfinite(st.nservers) || st.nservers < 1)
54 return false;
55 if (sn.mapc_of(ist, r) != nullptr) return false;
56 const lang::Distrib<T>& d = sn.service[ist - 1][r - 1];
57 if (d.disabled) return false;
58 if (d.type != lang::ProcessType::MAP && d.type != lang::ProcessType::MMPP2) return false;
59 return d.D0.rows() > 0 && d.D1.rows() == d.D0.rows();
60}
61
62/** Rewrite class r at station ist into pair form (c > 1) or mark it carried (c = 1); a private copy. */
63template <class T>
64void mapc_class(qn::NetworkStruct<T>& sn, std::size_t ist, std::size_t r) {
65 lang::Distrib<T>& d = sn.service[ist - 1][r - 1];
66 const T zero = num_traits<T>::from_int(0);
67 const std::size_t p = d.D0.rows();
68 if (sn.stations[ist - 1].nservers == 1) {
70 mc1.p = p;
71 mc1.single = true;
72 sn.ctmcmapc[std::make_pair(ist, r)] = mc1;
73 return;
74 }
75 Matrix<T> nD0(p, p, zero);
76 for (std::size_t i = 0; i < p; ++i)
77 for (std::size_t j = 0; j < p; ++j) nD0(i, j) = T(zero - d.D0(i, j));
78 Matrix<T> V = matmul(inverse(nD0), d.D1);
80 mc.p = p;
81 std::vector<std::vector<long>> tp(p, std::vector<long>(p, -1));
82 for (std::size_t i = 0; i < p; ++i)
83 for (std::size_t j = 0; j < p; ++j) {
84 if (std::fabs(num_traits<T>::to_double(V(i, j))) < 1e-14) V(i, j) = zero;
85 if (num_traits<T>::to_double(V(i, j)) > 0) {
86 tp[i][j] = static_cast<long>(mc.pairs.size());
87 mc.pairs.push_back(std::make_pair(i, j));
88 }
89 }
90 const std::size_t np = mc.pairs.size();
91 Matrix<T> D0p(np, np, zero), D1p(np, np, zero);
92 mc.done.assign(np, zero);
93 for (std::size_t t = 0; t < np; ++t) {
94 const std::size_t i = mc.pairs[t].first, j = mc.pairs[t].second;
95 mc.done[t] = T(d.D1(i, j) / V(i, j));
96 D0p(t, t) = d.D0(i, i);
97 for (std::size_t k = 0; k < p; ++k)
98 if (k != i && num_traits<T>::to_double(d.D0(i, k)) != 0 && tp[k][j] >= 0)
99 D0p(t, static_cast<std::size_t>(tp[k][j])) = T(d.D0(i, k) * V(k, j) / V(i, j));
100 for (std::size_t jn = 0; jn < p; ++jn)
101 if (tp[j][jn] >= 0) D1p(t, static_cast<std::size_t>(tp[j][jn])) = T(mc.done[t] * V(j, jn));
102 }
103 mc.V = V;
104 d.D0 = D0p; // same law, so type, mean and scv are kept
105 d.D1 = D1p;
106 sn.ctmcmapc[std::make_pair(ist, r)] = mc;
107}
108
109} // namespace mapc_detail
110
111/**
112 * Rewrite a copy of `in` into `out` when it has a MAP service at an FCFS station; false,
113 * leaving `out` untouched, when there is nothing to rewrite. Idempotent. A declared initial
114 * state at a rewritten station is carried as its marginal and rebuilt in the pair layout.
115 */
116template <class T>
118 const std::size_t R = in.nclasses;
119 bool any = false;
120 for (std::size_t ist = 1; ist <= in.stations.size() && !any; ++ist)
121 for (std::size_t r = 1; r <= R && !any; ++r) any = mapc_detail::wants_mapc(in, ist, r);
122 if (!any) return false;
123 out = in;
124 for (std::size_t ind = 1; ind <= in.nodes.size(); ++ind) {
125 const std::size_t ist = in.nodes[ind - 1].station;
126 if (ist == 0) continue;
127 bool changed = false;
128 for (std::size_t r = 1; r <= R; ++r)
129 if (mapc_detail::wants_mapc(in, ist, r)) {
130 mapc_detail::mapc_class(out, ist, r);
131 changed = true;
132 }
133 if (!changed) continue;
134 const auto sp = in.statespace.find(ind);
135 if (sp == in.statespace.end() || sp->second.rows() == 0) continue;
136 if (sp->second.rows() > 1)
137 throw UnsupportedError("SolverCTMC cannot place a distribution over initial states on "
138 "the MAP service of station '" + in.nodes[ind - 1].name + "'.");
139 std::vector<T> row(sp->second.cols());
140 for (std::size_t c = 0; c < sp->second.cols(); ++c) row[c] = sp->second(0, c);
141 const std::pair<T, std::vector<T>> mg = qn::to_marginal_aggr(in, ind, row);
143 for (std::size_t r = 0; r < R; ++r) m(0, r) = mg.second[r];
144 out.statespace[ind] = m;
145 }
146 return true;
147}
148
149} // namespace ctmc
150} // namespace line
151
152#endif // LINE_SOLVERS_CTMC_SOLVER_CTMC_MAPC_H
UnsupportedError(const std::string &what)
Definition error.h:51
A network plus its refreshed NetworkStruct.
std::vector< Station< T > > stations
stations[k-1] is the k-th station
std::vector< NodeDef > nodes
every node, in creation order
std::map< std::size_t, Matrix< T > > statespace
What refreshProcessRepresentations and refreshLST compute FROM a distribution: the (D0,...
The exception types the port throws.
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
Dense matrix and non-owning view.
bool wants_mapc(const qn::NetworkStruct< T > &sn, std::size_t ist, std::size_t r)
void mapc_class(qn::NetworkStruct< T > &sn, std::size_t ist, std::size_t r)
Rewrite class r at station ist into pair form (c > 1) or mark it carried (c = 1); a private copy.
bool ctmc_mapc(const qn::NetworkStruct< T > &in, qn::NetworkStruct< T > &out)
Rewrite a copy of in into out when it has a MAP service at an FCFS station; false,...
std::pair< T, std::vector< T > > to_marginal_aggr(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &state_i)
Port of State.toMarginalAggr: the job counts of one node's state row, without the per-phase detail to...
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
Matrix< T > inverse(const Matrix< T > &A)
Inverse by LU with one factorization and n back substitutions.
Definition linalg.h:72
Matrix< T > matmul(const Matrix< T > &A, const Matrix< T > &B)
Matrix product A B.
Definition linalg.h:36
A queueing network and its refreshed NetworkStruct.
Port of the event half of MATLAB's +State package: the successor states an event produces at one node...
Matrix< T > D0
The (D0,D1) pair when the type carries one directly.
Definition lang_types.h:853
CTMC pair form of a MAP service at an FCFS station, written by ctmc::ctmc_mapc on the solver's privat...
std::size_t p
phases of the original MAP
bool single
c = 1: carried phase, no pairs
One station of the network.
SchedStrategy sched
double nservers
may be infinite (a Delay, or an inf-scheduled task)