80 const std::vector<double>& K, std::vector<bool> isdelay,
81 double tol = 0.0,
long iter_max = 100000) {
83 const std::size_t M = S.size();
84 const T zero = nt::from_int(0);
85 const T one = nt::from_int(1);
86 const double inf = std::numeric_limits<double>::infinity();
87 if (isdelay.empty()) isdelay.assign(M,
false);
88 const std::string caller =
"pfqn_debemva: ";
90 throw InputError(
ErrorKind{
"Argument"}, caller +
"debeMVA requires a positive integer population N.");
91 if (P.rows() != M || P.cols() != M || K.size() != M || isdelay.size() != M)
93 caller +
"debeMVA requires S, K and isdelay of length M and an M x M routing matrix P.");
94 std::vector<double> B(M, inf);
95 for (std::size_t i = 0; i < M; ++i) {
96 const double s = nt::to_double(S[i]);
97 if (!(s >= 0.0) || !std::isfinite(s))
98 throw InputError(
ErrorKind{
"Argument"}, caller +
"debeMVA requires finite nonnegative service times.");
99 if (!isdelay[i] && !(K[i] >= 1.0))
101 caller +
"debeMVA requires every queue capacity K(i) to be at least 1.");
102 B[i] = (isdelay[i] || K[i] >=
static_cast<double>(N)) ? inf : K[i];
104 for (std::size_t j = 0; j < M; ++j) {
105 const double p = nt::to_double(P(i, j));
107 throw InputError(
ErrorKind{
"Argument"}, caller +
"debeMVA requires a row-stochastic routing matrix P.");
110 if (std::fabs(row - 1.0) > 1e-8)
111 throw InputError(
ErrorKind{
"Argument"}, caller +
"debeMVA requires a row-stochastic routing matrix P.");
113 std::vector<std::vector<bool>> reach(M, std::vector<bool>(M,
false));
114 for (std::size_t i = 0; i < M; ++i)
115 for (std::size_t j = 0; j < M; ++j) reach[i][j] = i == j || P(i, j) > zero;
116 const int squarings =
static_cast<int>(std::ceil(std::log2(
static_cast<double>(M < 2 ? 2 : M)))) + 1;
117 for (
int h = 0; h < squarings; ++h) {
118 std::vector<std::vector<bool>> next(M, std::vector<bool>(M,
false));
119 for (std::size_t i = 0; i < M; ++i)
120 for (std::size_t j = 0; j < M; ++j) {
121 bool r = reach[i][j];
122 for (std::size_t l = 0; l < M && !r; ++l) r = reach[i][l] && reach[l][j];
127 for (std::size_t i = 0; i < M; ++i)
128 for (std::size_t j = 0; j < M; ++j)
131 caller +
"debeMVA requires a routing matrix that is irreducible on the stations.");
133 std::vector<std::vector<double>> W(M, std::vector<double>(M, inf));
134 for (std::size_t i = 0; i < M; ++i)
135 for (std::size_t j = 0; j < M; ++j)
136 if (i != j && P(i, j) > zero && std::isfinite(B[j])) W[i][j] = B[j];
137 for (std::size_t h = 0; h < M; ++h)
138 for (std::size_t i = 0; i < M; ++i)
139 for (std::size_t j = 0; j < M; ++j)
140 if (W[i][h] + W[h][j] < W[i][j]) W[i][j] = W[i][h] + W[h][j];
142 for (std::size_t i = 0; i < M; ++i)
143 if (W[i][i] < cyc) cyc = W[i][i];
144 if (
static_cast<double>(N) >= cyc)
146 caller +
"debeMVA requires N below the total capacity " + std::to_string(cyc) +
147 " of every cycle of finite stations, to rule out a deadlock of the blocking network; N = " +
148 std::to_string(N) +
".");
153 std::vector<T> e(M, zero);
154 for (std::size_t i = 0; i < M; ++i)
155 for (std::size_t j = 0; j < M; ++j) A(i, j) = T(P(j, i) - (i == j ? one : zero));
156 for (std::size_t j = 0; j < M; ++j) A(0, j) = j == 0 ? one : zero;
158 for (std::size_t c = 0; c < M; ++c) {
160 for (std::size_t r = c + 1; r < M; ++r)
161 if (std::fabs(nt::to_double(A(r, c))) > std::fabs(nt::to_double(A(piv, c)))) piv = r;
163 for (std::size_t j = 0; j < M; ++j) std::swap(A(c, j), A(piv, j));
164 std::swap(e[c], e[piv]);
166 for (std::size_t r = 0; r < M; ++r) {
167 if (r == c || A(r, c) == zero)
continue;
168 const T f = T(A(r, c) / A(c, c));
169 for (std::size_t j = c; j < M; ++j) A(r, j) = T(A(r, j) - f * A(c, j));
170 e[r] = T(e[r] - f * e[c]);
173 for (std::size_t i = 0; i < M; ++i) e[i] = T(e[i] / A(i, i));
176 std::vector<T> Bt(M, zero);
177 std::vector<bool> fin(M,
false);
178 std::vector<int> nd(M, 0);
181 for (std::size_t i = 0; i < M; ++i) {
182 fin[i] = std::isfinite(B[i]);
184 Bt[i] = nt::from_double(B[i]);
185 if (!anyFin || S[i] > smax) smax = S[i];
188 for (std::size_t l = 0; l < M; ++l)
189 if (P(i, l) > zero) ++nd[i];
191 std::vector<bool> slow(M,
false);
192 for (std::size_t i = 0; i < M; ++i) slow[i] = fin[i] && S[i] == smax;
193 const T tolT = nt::from_double(tol);
196 std::vector<T> z(M, one), bt(M, zero), n(M, zero), t(S), X(M, zero), beta(M, zero);
197 std::vector<bool> first(M,
false);
198 for (
long k = 1; k <= N; ++k) {
199 const std::vector<T> nprev = n;
200 const T kT = nt::from_int(k);
201 for (std::size_t j = 0; j < M; ++j)
202 beta[j] = (fin[j] && B[j] <
static_cast<double>(k)) ? T(one - Bt[j] / kT) : zero;
204 for (std::size_t j = 0; j < M; ++j) {
205 if (slow[j] &&
static_cast<double>(k) > B[j] + 1.0 && !first[j]) {
207 for (std::size_t i = 0; i < M; ++i)
208 if (i != j && P(i, j) > zero) {
209 z[i] = T(z[i] + P(i, j) * z[j] * beta[j]);
210 bt[i] = T(bt[i] + P(i, j) * S[j] * T(S[j] / T(S[j] + S[i])));
212 z[j] = T(z[j] - z[j] * beta[j]);
215 for (std::size_t j = 0; j < M; ++j) {
216 if (!(slow[j] &&
static_cast<double>(k) > B[j] + 1.0))
continue;
217 for (std::size_t i = 0; i < M; ++i) {
218 if (i == j || !(P(i, j) > zero) || nd[i] <= 1)
continue;
219 for (std::size_t l = 0; l < M; ++l)
220 if (l != j && P(i, l) > zero) z[l] = T(z[l] + z[i] * beta[j] * P(i, l));
221 z[i] = T(z[i] - z[i] * beta[j]);
230 for (std::size_t i = 0; i < M; ++i) {
231 t[i] = isdelay[i] ? T(S[i] + bt[i] / kT) : T(S[i] * (z[i] + nprev[i]) + bt[i]);
232 denom = T(denom + e[i] * t[i]);
234 for (std::size_t i = 0; i < M; ++i) {
235 X[i] = T(kT * e[i] / denom);
236 n[i] = T(t[i] * X[i]);
239 for (std::size_t j = 0; j < M; ++j) {
240 if (fin[j] && n[j] > T(Bt[j] + tolT)) {
243 for (std::size_t i = 0; i < M; ++i)
244 if (i != j && P(i, j) > zero && (isdelay[i] || !fin[i] || n[i] < Bt[i])) {
245 z[i] = T(z[i] + P(i, j) * z[j] * beta[j]);
246 bt[i] = T(bt[i] + P(i, j) * S[j] * T(S[j] / T(S[j] + S[i])));
248 z[j] = T(z[j] - z[j] * beta[j]);
249 }
else if (n[j] < nprev[j]) {
250 const T d = T(nprev[j] - n[j]);
253 for (std::size_t i = 0; i < M; ++i)
254 if (i != j && P(i, j) > zero) den = T(den + P(i, j));
256 for (std::size_t i = 0; i < M; ++i)
257 if (i != j && P(i, j) > zero) n[i] = T(n[i] - P(i, j) * d / den);
261 if (passes >= iter_max) {
272 res.
U.assign(M, zero);
273 for (std::size_t i = 0; i < M; ++i) res.
U[i] = T(X[i] * S[i]);