76 const std::vector<double>& K, std::vector<bool> isdelay,
77 double tol = 1e-4,
int iter_max = 1000) {
79 const std::size_t M = S.size();
80 const T zero = nt::from_int(0);
81 const T one = nt::from_int(1);
82 if (isdelay.empty()) isdelay.assign(M,
false);
83 const std::string caller =
"pfqn_mvablo: ";
85 throw InputError(
ErrorKind{
"Argument"}, caller +
"MVABLO requires a positive integer population N.");
86 if (P.rows() != M || P.cols() != M || K.size() != M || isdelay.size() != M)
88 caller +
"MVABLO requires S, K and isdelay of length M and an M x M routing matrix P.");
90 bool anyDelay =
false;
91 for (std::size_t i = 0; i < M; ++i) {
92 const double s = nt::to_double(S[i]);
93 if (!(s >= 0.0) || !std::isfinite(s))
94 throw InputError(
ErrorKind{
"Argument"}, caller +
"MVABLO requires finite nonnegative service times.");
95 if (!isdelay[i] && !(K[i] >= 1.0))
97 caller +
"MVABLO requires every queue capacity K(i) to be at least 1.");
99 anyDelay = anyDelay || isdelay[i];
101 for (std::size_t j = 0; j < M; ++j) {
102 const double p = nt::to_double(P(i, j));
104 throw InputError(
ErrorKind{
"Argument"}, caller +
"MVABLO requires a row-stochastic routing matrix P.");
107 if (std::fabs(row - 1.0) > 1e-8)
108 throw InputError(
ErrorKind{
"Argument"}, caller +
"MVABLO requires a row-stochastic routing matrix P.");
110 std::vector<std::vector<bool>> reach(M, std::vector<bool>(M,
false));
111 for (std::size_t i = 0; i < M; ++i)
112 for (std::size_t j = 0; j < M; ++j) reach[i][j] = i == j || P(i, j) > zero;
113 const int squarings =
static_cast<int>(std::ceil(std::log2(
static_cast<double>(M < 2 ? 2 : M)))) + 1;
114 for (
int h = 0; h < squarings; ++h) {
115 std::vector<std::vector<bool>> next(M, std::vector<bool>(M,
false));
116 for (std::size_t i = 0; i < M; ++i)
117 for (std::size_t j = 0; j < M; ++j) {
118 bool r = reach[i][j];
119 for (std::size_t l = 0; l < M && !r; ++l) r = reach[i][l] && reach[l][j];
124 for (std::size_t i = 0; i < M; ++i)
125 for (std::size_t j = 0; j < M; ++j)
128 caller +
"MVABLO requires a routing matrix that is irreducible on the stations.");
129 if (!anyDelay &&
static_cast<double>(N) >= sumK)
131 caller +
"MVABLO requires N < sum(K) = " + std::to_string(sumK) +
132 " to rule out a deadlock of the blocking network; N = " + std::to_string(N) +
".");
137 std::vector<T> e(M, zero);
138 for (std::size_t i = 0; i < M; ++i)
139 for (std::size_t j = 0; j < M; ++j) A(i, j) = T(P(j, i) - (i == j ? one : zero));
140 for (std::size_t j = 0; j < M; ++j) A(0, j) = j == 0 ? one : zero;
142 for (std::size_t c = 0; c < M; ++c) {
144 for (std::size_t r = c + 1; r < M; ++r)
145 if (std::fabs(nt::to_double(A(r, c))) > std::fabs(nt::to_double(A(piv, c)))) piv = r;
147 for (std::size_t j = 0; j < M; ++j) std::swap(A(c, j), A(piv, j));
148 std::swap(e[c], e[piv]);
150 for (std::size_t r = 0; r < M; ++r) {
151 if (r == c || A(r, c) == zero)
continue;
152 const T f = T(A(r, c) / A(c, c));
153 for (std::size_t j = c; j < M; ++j) A(r, j) = T(A(r, j) - f * A(c, j));
154 e[r] = T(e[r] - f * e[c]);
157 for (std::size_t i = 0; i < M; ++i) e[i] = T(e[i] / A(i, i));
159 std::vector<T> q(M, zero), z(M, one), t(M, zero);
163 for (
long n = 1; n <= N; ++n) {
164 const std::vector<T> qprev = q;
170 for (std::size_t i = 0; i < M; ++i) {
172 for (std::size_t j = 0; j < M; ++j) bsum = T(bsum + bt(i, j));
173 t[i] = isdelay[i] ? T(S[i] + bsum) : T(S[i] * (z[i] + qprev[i]) + bsum);
174 denom = T(denom + e[i] * t[i]);
176 lambda = T(nt::from_int(n) / denom);
177 std::vector<bool> full(M,
false);
178 bool anyFull =
false;
179 for (std::size_t i = 0; i < M; ++i) {
180 q[i] = T(e[i] * lambda * t[i]);
181 full[i] = !isdelay[i] && std::isfinite(K[i]) && q[i] > nt::from_double(K[i] + tol);
182 anyFull = anyFull || full[i];
185 if (passes >= iter_max) {
189 for (std::size_t i = 0; i < M; ++i) {
190 if (!full[i])
continue;
192 for (std::size_t j = 0; j < M; ++j)
193 if (j != i && P(j, i) > zero) bt(j, i) = T(bt(j, i) + S[i] * P(j, i) * e[j] / e[i]);
197 res.
X.assign(M, zero);
198 res.
U.assign(M, zero);
199 for (std::size_t i = 0; i < M; ++i) {
200 res.
X[i] = T(e[i] * lambda);
201 res.
U[i] = T(res.
X[i] * S[i]);