5#ifndef LINE_API_PFQN_MVAC_H
6#define LINE_API_PFQN_MVAC_H
91 std::size_t J1 = 0, J = 0, D = 0, S = 0;
94 std::vector<std::size_t> posr;
95 std::vector<std::size_t> grpOfClass;
96 std::vector<std::size_t> gorder;
97 std::vector<std::vector<int>> Vlist;
98 std::vector<int> vsum;
99 std::vector<std::size_t> off, cnt;
104MvacSetup<T> mvac_setup(
const Matrix<T>& A,
const std::vector<int>& N, std::size_t J1,
105 std::size_t J, std::size_t K) {
112 for (std::size_t r = 0; r < N.size(); ++r)
113 if (N[r] > 0) st.posr.push_back(r);
116 std::vector<std::vector<T>> Adist;
117 st.grpOfClass.assign(st.posr.size(), 0);
118 for (std::size_t p = 0; p < st.posr.size(); ++p) {
119 std::vector<T> colv(J, zero);
120 for (std::size_t j = 0; j < J; ++j) colv[j] = A(j, st.posr[p]);
121 std::size_t g = Adist.size();
122 for (std::size_t q = 0; q < Adist.size(); ++q)
123 if (Adist[q] == colv) {
127 if (g == Adist.size()) Adist.push_back(colv);
128 st.grpOfClass[p] = g;
130 const std::size_t Dall = Adist.size();
132 std::vector<bool> visitsIS(Dall,
false);
133 for (std::size_t g = 0; g < Dall; ++g)
134 for (std::size_t j = J1; j < J; ++j)
135 if (Adist[g][j] > zero) {
139 for (std::size_t g = 0; g < Dall; ++g)
140 if (visitsIS[g]) st.gorder.push_back(g);
141 for (std::size_t g = 0; g < Dall; ++g)
142 if (!visitsIS[g]) st.gorder.push_back(g);
145 for (std::size_t g = 0; g < Dall; ++g)
146 if (!visitsIS[g]) ++st.S;
149 std::vector<std::size_t> mult(st.D, 0);
150 for (std::size_t g = 0; g < st.D; ++g)
151 for (std::size_t p = 0; p < st.posr.size(); ++p)
152 if (st.grpOfClass[p] == st.gorder[g])
153 mult[g] +=
static_cast<std::size_t
>(N[st.posr[p]]);
154 std::vector<std::size_t> chainGroup(K, 0);
155 for (std::size_t g = 0; g < st.D; ++g) chainGroup[K - st.D + g] = g;
157 for (std::size_t g = 0; g < st.D; ++g)
158 for (std::size_t cc = 0; cc + 1 < mult[g]; ++cc) chainGroup[p++] = g;
161 for (std::size_t k = 0; k < K; ++k)
162 for (std::size_t j = 0; j < J; ++j) st.a(j, k) = Adist[st.gorder[chainGroup[k]]][j];
165 st.off.assign(K + 1, 0);
166 st.cnt.assign(K + 1, 0);
167 for (std::size_t t = 0; t <= K; ++t) {
168 const std::vector<std::vector<int>> Vt =
170 st.off[t] = st.Vlist.size();
171 st.cnt[t] = Vt.size();
172 for (std::size_t i = 0; i < Vt.size(); ++i) {
173 st.Vlist.push_back(Vt[i]);
174 st.vsum.push_back(
static_cast<int>(t));
177 const std::size_t nv = st.Vlist.size();
178 st.succ = Matrix<long>(nv, J, -1);
179 for (std::size_t vi = 0; vi < nv; ++vi) {
180 const int t = st.vsum[vi];
181 if (
static_cast<std::size_t
>(t) + 1 > K)
continue;
182 for (std::size_t j = 0; j < J; ++j) {
183 std::vector<int> w = st.Vlist[vi];
185 for (std::size_t q = 0; q < st.cnt[t + 1]; ++q)
186 if (st.Vlist[st.off[t + 1] + q] == w) {
187 st.succ(vi, j) =
static_cast<long>(st.off[t + 1] + q);
197void mvac_part1(std::size_t k0,
const MvacSetup<T>& st, std::vector<Matrix<T>>& Lall,
198 std::vector<Matrix<T>>& Ljkall, std::vector<std::vector<T>>& lamall) {
199 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
200 const std::size_t J = st.J, J1 = st.J1, K = st.K, nv = st.Vlist.size();
201 for (std::size_t k = k0; k <= K; ++k) {
202 const Matrix<T>& Lp = Lall[k - 1];
203 Matrix<T> Lk(J, nv, zero), Ljk(J, nv, zero);
204 std::vector<T> lamv(nv, zero);
205 for (std::size_t vi = 0; vi < nv; ++vi) {
206 if (
static_cast<std::size_t
>(st.vsum[vi]) > K - k)
continue;
208 for (std::size_t j = 0; j < J; ++j) den += st.a(j, k - 1);
209 for (std::size_t j = 0; j < J1; ++j)
210 den += (Lp(j, vi) + num_traits<T>::from_int(st.Vlist[vi][j])) * st.a(j, k - 1);
211 if (den <= zero)
throw NumericError(ErrorKind{
"Degenerate"},
"pfqn_mvac: a chain has zero total demand");
212 const T lam = one / den;
213 for (std::size_t j = 0; j < J1; ++j)
214 Ljk(j, vi) = lam * (one + Lp(j, vi) + num_traits<T>::from_int(st.Vlist[vi][j])) *
216 for (std::size_t j = J1; j < J; ++j) Ljk(j, vi) = lam * st.a(j, k - 1);
218 for (std::size_t i = 0; i < J; ++i) {
220 for (std::size_t j = 0; j < J; ++j) {
221 const long sj = st.succ(vi, j);
222 if (sj < 0)
throw NumericError(ErrorKind{
"Degenerate"},
"pfqn_mvac: multiplicity vector out of range");
223 s += Ljk(j, vi) * Lp(i,
static_cast<std::size_t
>(sj));
247 const std::size_t M = L.
rows(), R = L.
cols();
250 if (R == 0)
throw InputError(
"pfqn_mvac: empty demand matrix");
251 if (N.size() != R)
throw InputError(
"pfqn_mvac: L and N disagree on the class count");
253 throw InputError(
"pfqn_mvac: the think time matrix and the demand matrix disagree");
257 res.
X.assign(R, zero);
263 for (std::size_t r = 0; r < R; ++r) {
264 if (N[r] < 0)
throw InputError(
"pfqn_mvac: the population vector must be nonnegative");
265 K +=
static_cast<std::size_t
>(N[r]);
267 if (K == 0)
return res;
270 std::vector<std::size_t> ssfrIdx, isIdx;
271 for (std::size_t i = 0; i < M; ++i)
272 for (std::size_t r = 0; r < R; ++r)
273 if (L(i, r) > zero) {
274 ssfrIdx.push_back(i);
277 for (std::size_t i = 0; i < Z.
rows(); ++i)
278 for (std::size_t r = 0; r < R; ++r)
279 if (Z(i, r) > zero) {
283 const std::size_t J1 = ssfrIdx.size(), J = J1 + isIdx.size();
284 if (J == 0)
throw InputError(
"pfqn_mvac: all service demands are zero, the throughput is unbounded");
287 for (std::size_t j = 0; j < J1; ++j)
288 for (std::size_t r = 0; r < R; ++r) A(j, r) = L(ssfrIdx[j], r);
289 for (std::size_t j = J1; j < J; ++j)
290 for (std::size_t r = 0; r < R; ++r) A(j, r) = Z(isIdx[j - J1], r);
292 detail::MvacSetup<T> st = detail::mvac_setup(A, N, J1, J, K);
293 const std::size_t nv = st.Vlist.size();
294 const std::size_t z0 = 0;
296 std::vector<Matrix<T>> Lall(K + 1), Ljkall(K + 1);
297 std::vector<std::vector<T>> lamall(K + 1);
300 std::vector<T> lamChain(K, zero);
303 detail::mvac_part1(1, st, Lall, Ljkall, lamall);
304 lamChain[K - 1] = lamall[K][z0];
305 for (std::size_t j = 0; j < J; ++j) Lchain(j, K - 1) = Ljkall[K](j, z0);
308 const std::size_t D = st.D, S = st.S;
309 const long lmaxK = std::min(
static_cast<long>(K) - 1,
static_cast<long>(K - S));
310 if (D >= 2 && lmaxK >=
static_cast<long>(K - D + 1)) {
311 std::vector<Matrix<T>> L2prev(K + 1), L2cur(K + 1);
312 for (std::size_t k = K - D + 2; k <= K; ++k) {
314 const long lhi = std::min(
static_cast<long>(k) - 1,
static_cast<long>(K - S));
315 for (
long l =
static_cast<long>(K - D + 1); l <= lhi; ++l) {
317 for (std::size_t vi = 0; vi < nv; ++vi) {
318 if (
static_cast<std::size_t
>(st.vsum[vi]) != K - k)
continue;
319 for (std::size_t j = 0; j < J; ++j) {
320 const long sj = st.succ(vi, j);
321 if (sj < 0)
throw NumericError(
ErrorKind{
"Degenerate"},
"pfqn_mvac: multiplicity vector out of range");
323 (l ==
static_cast<long>(k) - 1) ? Ljkall[k - 1] : L2prev[l];
324 for (std::size_t i = 0; i < J; ++i)
325 acc(i, vi) += Ljkall[k](j, vi) * prev(i,
static_cast<std::size_t
>(sj));
331 for (
long l =
static_cast<long>(K - D + 1); l <= lmaxK; ++l) {
332 for (std::size_t j = 0; j < J; ++j)
333 Lchain(j,
static_cast<std::size_t
>(l) - 1) = L2cur[l](j, z0);
335 for (std::size_t j = J1; j < J; ++j)
336 if (st.a(j,
static_cast<std::size_t
>(l) - 1) > zero) {
341 lamChain[
static_cast<std::size_t
>(l) - 1] =
342 Lchain(jIS,
static_cast<std::size_t
>(l) - 1) /
343 st.a(jIS,
static_cast<std::size_t
>(l) - 1);
351 std::vector<std::size_t>
perm(K);
352 for (std::size_t k = 0; k < K; ++k)
perm[k] = k;
353 for (std::size_t l = 1; l + 1 <= S && S >= 1 && l < S; ++l) {
354 std::swap(
perm[K - l - 1],
perm[K - 1]);
355 for (std::size_t j = 0; j < J; ++j) {
356 const T tmp = st.a(j, K - l - 1);
357 st.a(j, K - l - 1) = st.a(j, K - 1);
358 st.a(j, K - 1) = tmp;
360 detail::mvac_part1(K - l, st, Lall, Ljkall, lamall);
361 lamChain[
perm[K - 1]] = lamall[K][z0];
362 for (std::size_t j = 0; j < J; ++j) Lchain(j,
perm[K - 1]) = Ljkall[K](j, z0);
366 for (std::size_t g = 0; g < D; ++g) {
367 const std::size_t kg = K - D + g;
368 for (std::size_t p = 0; p < st.posr.size(); ++p) {
369 if (st.grpOfClass[p] != st.gorder[g])
continue;
370 const std::size_t r = st.posr[p];
372 res.
X[r] = nr * lamChain[kg];
373 for (std::size_t j = 0; j < J1; ++j) {
374 res.
Q(ssfrIdx[j], r) = nr * Lchain(j, kg);
375 res.
U(ssfrIdx[j], r) = res.
X[r] * L(ssfrIdx[j], r);
376 res.
C(ssfrIdx[j], r) = res.
Q(ssfrIdx[j], r) / res.
X[r];
381 for (std::size_t r = 0; r < R; ++r)
383 for (std::size_t i = 0; i < M; ++i) res.
C(i, r) = L(i, r);
NumericError(const std::string &what)
The exception types the port throws.
Dense matrix and non-owning view.
std::vector< std::vector< int > > multichoose_rows(int n, int k)
All n-vectors of nonnegative integers summing to k, in MATLAB multichoose(n,k) order.
MvacResult< T > pfqn_mvac(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z)
MVAC: exact mean value analysis BY CHAIN of a closed multichain product-form network (Conway,...
Conservation laws of a layered queueing network, enumerated from its structure.
Number-type abstraction for the templated API port.
Integer-composition enumeration shared by the CoMoM and MVAC ports.
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
Return value of pfqn_mvac, mirroring [XN, QN, UN, CN].
Matrix< T > C
(M x R) per-class residence time
Matrix< T > U
(M x R) per-class utilization
std::vector< T > X
(R) per-class throughput
Matrix< T > Q
(M x R) per-class queue length at the SSFR queues