5#ifndef LINE_SOLVERS_MVA_SN_CHAIN_H
6#define LINE_SOLVERS_MVA_SN_CHAIN_H
41using lang::GlobalConstants;
70 std::vector<std::vector<bool>> st_inf(M, std::vector<bool>(K,
false));
72 std::vector<std::vector<bool>> scv_known(M, std::vector<bool>(K,
true));
73 for (std::size_t i = 0; i < M; ++i)
74 for (std::size_t r = 0; r < K; ++r) {
82 if (L.
rates(i, r) == zero) {
88 d.
ST(i, r) = T(one / L.
rates(i, r));
90 SCV(i, r) = L.
scv(i, r);
95 std::vector<std::vector<bool>> v_bad(M, std::vector<bool>(C,
false));
97 for (std::size_t c = 0; c < C; ++c) {
98 const std::vector<std::size_t>& ic = L.
inchain[c];
99 const std::size_t rstat = L.
classes[ic[0] - 1].refstat;
107 for (std::size_t k : ic) den += L.
visits[c](rsf, k - 1);
109 for (std::size_t i = 0; i < M; ++i) {
112 for (std::size_t k : ic) num += L.
visits[c](sf, k - 1);
116 d.
Vchain(i, c) = T(num / den);
118 for (std::size_t k : ic)
122 for (std::size_t i = 0; i < M; ++i)
123 for (std::size_t c = 0; c < C; ++c)
124 if (v_bad[i][c]) d.
Vchain(i, c) = zero;
127 for (std::size_t c = 0; c < C; ++c) {
129 const T vref = d.
Vchain(rstat - 1, c);
130 if (vref == zero)
continue;
131 for (std::size_t i = 0; i < M; ++i) d.
Vchain(i, c) = T(d.
Vchain(i, c) / vref);
133 for (std::size_t i = 0; i < M; ++i)
134 for (std::size_t k = 0; k < K; ++k)
136 d.
alpha(i, k) = zero;
144 for (std::size_t c = 0; c < C; ++c) {
145 const std::vector<std::size_t>& ic = L.
inchain[c];
148 for (std::size_t k : ic) {
149 const double p = L.
classes[k - 1].population;
150 if (std::isinf(p)) open =
true;
153 d.
Nchain[c] = open ? std::numeric_limits<double>::infinity() : n;
154 const std::size_t rstat = L.
classes[ic[0] - 1].refstat;
157 for (std::size_t i = 0; i < M; ++i) {
160 for (std::size_t k : ic) {
161 if (st_inf[i][k - 1] && d.
alpha(i, k - 1) != zero) bad =
true;
162 st += d.
ST(i, k - 1) * d.
alpha(i, k - 1);
164 if (open && i + 1 == rstat) {
167 for (std::size_t k : ic)
174 d.
STchain(i, c) = bad ? zero : st;
178 for (std::size_t k : ic) ach += d.
alpha(i, k - 1);
181 for (std::size_t k : ic) s += SCV(i, k - 1) * d.
alpha(i, k - 1);
217 const std::vector<T>& Xchain) {
228 std::vector<T> Vsink(K, zero);
230 for (std::size_t c = 0; c < L.
nchains; ++c)
233 for (std::size_t c = 0; c < L.
nchains; ++c) {
234 const std::vector<std::size_t>& ic = L.
inchain[c];
235 const bool open = std::isinf(d.
Nchain[c]);
238 "sn_deaggregate_chain_results: an open chain needs the Sink node visits, and this "
239 "layer has no Sink node to read them from");
240 for (std::size_t kk : ic) {
241 const std::size_t k = kk - 1;
242 const std::size_t rstat = L.
classes[k].refstat;
243 r.
X[k] = open ? T(Xchain[c] * Vsink[k]) : T(Xchain[c] * d.
alpha(rstat - 1, k));
244 const T vref = d.
Vchain(rstat - 1, c);
245 for (std::size_t i = 0; i < M; ++i) {
246 const double S = L.
stations[i].nservers;
248 const T base = T(d.
ST(i, k) * (Xchain[c] * d.
Vchain(i, c) / vref) *
252 }
else if (Uchain.
rows() == 0) {
255 r.
U(i, k) = T(Uchain(i, c) * d.
alpha(i, k));
258 if (d.
Lchain(i, c) > zero) {
259 if (Qchain.
rows() > 0) {
260 r.
Q(i, k) = T(Qchain(i, c) * d.
alpha(i, k));
261 }
else if (d.
STchain(i, c) != zero && vref != zero) {
262 r.
Q(i, k) = T(Rchain(i, c) * d.
ST(i, k) / d.
STchain(i, c) * Xchain[c] *
265 r.
Tp(i, k) = T(Tchain(i, c) * d.
alpha(i, k));
266 r.
R(i, k) = r.
Tp(i, k) == zero ? zero : T(r.
Q(i, k) / r.
Tp(i, k));
269 const double njobs = L.
classes[k].population;
270 r.
C[k] = r.
X[k] == zero ? zero
275 for (std::size_t i = 0; i < A.rows(); ++i)
276 for (std::size_t j = 0; j < A.cols(); ++j)
277 if (A(i, j) < zero) A(i, j) = T(-A(i, j));
284 if (x < zero) x = T(-x);
286 if (x < zero) x = T(-x);
296 std::vector<double>
N;
297 std::vector<double>
S;
313 for (std::size_t i = 0; i < L.
nstations; ++i) {
320 for (std::size_t c = 0; c < L.
nchains; ++c) {
331 std::size_t source_station = 0;
332 for (std::size_t i = 0; i < L.
nstations; ++i)
333 if (L.
stations[i].nodetype == qn::NodeType::Source) source_station = i + 1;
335 if (source_station > 0)
336 for (std::size_t c = 0; c < L.
nchains; ++c)
337 for (std::size_t r = 0; r < L.
nclasses; ++r) {
338 if (!L.
chains[c][r])
continue;
339 if (!std::isinf(L.
classes[r].population))
continue;
340 if (L.
disabled[source_station - 1][r])
continue;
359 const std::vector<std::vector<double>>& ILclass) {
362 if (ILclass.size() != R)
363 throw InputError(
"sn_interlock_chain: the interlock matrix disagrees with the class count");
367 for (std::size_t cr = 0; cr < K; ++cr)
368 for (std::size_t cs = 0; cs < K; ++cs) {
369 if (cr == cs)
continue;
371 for (std::size_t r = 0; r < R; ++r) {
372 if (!L.
chains[cr][r])
continue;
373 if (ILclass[r].size() != R)
374 throw InputError(
"sn_interlock_chain: the interlock matrix is not square");
375 for (std::size_t sIl = 0; sIl < R; ++sIl) {
376 if (!L.
chains[cs][sIl])
continue;
377 if (ILclass[r][sIl] > best) best = ILclass[r][sIl];
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
std::vector< Matrix< T > > nodevisits
(nchains) each (nnodes x nclasses)
std::size_t stateful_of_station(std::size_t st) const
std::vector< std::vector< bool > > chains
(nchains x nclasses)
std::vector< std::size_t > refclass
(nchains) 1-based class, 0 = none
std::vector< std::vector< bool > > disabled
std::vector< JobClass > classes
std::size_t sinkNode
1-based NODE index of the Sink, 0 = none (it is not a station)
std::vector< Station< T > > stations
stations[k-1] is the k-th station
Matrix< T > rates
(nstations x nclasses) service rates and SCVs, with a PARALLEL disabled flag instead of MATLAB's NaN ...
std::vector< std::vector< std::size_t > > inchain
1-based class indices per chain
std::vector< Matrix< T > > visits
(nchains) each (nstateful x nclasses)
The exception types the port throws.
Dense matrix and non-owning view.
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
PfChainParams< T > sn_get_product_form_chain_params(const qn::NetworkStruct< T > &L, const ChainDemands< T > &d)
Port of sn_get_product_form_chain_params.
Matrix< T > sn_interlock_chain(const qn::NetworkStruct< T > &L, const std::vector< std::vector< double > > &ILclass)
Aggregate a class-indexed interlock matrix to the chain basis the MVA analyzers work in.
ClassResults< T > sn_deaggregate_chain_results(const qn::NetworkStruct< T > &L, const ChainDemands< T > &d, const Matrix< T > &Qchain, const Matrix< T > &Uchain, const Matrix< T > &Rchain, const Matrix< T > &Tchain, const std::vector< T > &Xchain)
Port of sn_deaggregate_chain_results.
ChainDemands< T > sn_get_demands_chain(const qn::NetworkStruct< T > &L)
Port of sn_get_demands_chain.
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
The chain-level view of a layer, as sn_get_demands_chain returns it.
Matrix< T > ST
(M x K) class-level mean service time, 0 where disabled
std::vector< std::size_t > refstatchain
(C) 1-based reference station
std::vector< double > Nchain
(C) population, infinite for an open chain
Matrix< T > alpha
(M x K) class share of its chain's visits at a station
Matrix< T > STchain
(M x C) mean service time
Matrix< T > Lchain
(M x C) demand
Matrix< T > Vchain
(M x C) visits
Matrix< T > SCVchain
(M x C)
Class-level results, as sn_deaggregate_chain_results returns them.
static constexpr double Zero
Product-form chain parameters, the split into queueing and delay stations.
Matrix< T > D
(Mq x C) demands at queueing stations
std::vector< T > lambda
(C) chain arrival rates, zero on a closed chain
Matrix< T > Z
(Md x C) demands at delay stations
std::vector< std::size_t > delay_stations
1-based
std::vector< double > N
(C) populations
std::vector< std::size_t > queue_stations
1-based
std::vector< double > S
(Mq) server counts