172 const std::size_t M = L.
rows(), R = L.
cols();
173 if (M == 0 || R == 0)
throw InputError(
"pfqn_mvacld: empty demand matrix");
174 if (N.size() != R)
throw InputError(
"pfqn_mvacld: L and N disagree on the class count");
176 throw InputError(
"pfqn_mvacld: the think time matrix and the demand matrix disagree");
180 for (std::size_t r = 0; r < R; ++r) {
181 if (N[r] < 0)
throw InputError(
"pfqn_mvacld: the population vector must be nonnegative");
182 K +=
static_cast<std::size_t
>(N[r]);
186 res.
X.assign(R, zero);
188 res.
U.assign(M, zero);
189 res.
C.assign(R, zero);
191 for (std::size_t i = 0; i < M; ++i) res.
pij(i, 0) = one;
192 if (K == 0)
return res;
196 throw InputError(
"pfqn_mvacld: the rate matrix and the demand matrix disagree on centers");
198 throw InputError(
"pfqn_mvacld: the rate matrix must supply a rate for every population up to sum(N)");
201 std::vector<std::size_t> ldIdx, isIdx;
202 for (std::size_t i = 0; i < M; ++i)
203 for (std::size_t r = 0; r < R; ++r)
204 if (L(i, r) > zero) {
208 for (std::size_t i = 0; i < Z.
rows(); ++i)
209 for (std::size_t r = 0; r < R; ++r)
210 if (Z(i, r) > zero) {
214 const std::size_t J1 = ldIdx.size(), J = J1 + isIdx.size();
216 throw InputError(
"pfqn_mvacld: all service demands are zero, the throughput is unbounded");
219 for (std::size_t j = 0; j < J1; ++j)
220 for (std::size_t r = 0; r < R; ++r) A(j, r) = L(ldIdx[j], r);
221 for (std::size_t j = J1; j < J; ++j)
222 for (std::size_t r = 0; r < R; ++r) A(j, r) = Z(isIdx[j - J1], r);
226 for (std::size_t j = 0; j < J1; ++j)
227 for (std::size_t n = 0; n < K; ++n) {
228 if (mu(ldIdx[j], n) <= zero)
230 "pfqn_mvacld: the service rates must be strictly positive for every "
231 "population up to sum(N)");
232 MU(j, n) = mu(ldIdx[j], n);
235 detail::MvacSetup<T> st = detail::mvac_setup(A, N, J1, J, K);
236 const std::size_t D = st.D, S = st.S;
238 std::vector<Matrix<T>> Pall(K + 1), Ljkall(K + 1);
239 std::vector<std::vector<T>> lamall(K + 1);
240 Pall[0] =
Matrix<T>(J1 * st.cnt[K], 1, one);
242 std::vector<T> lamChain(K, zero);
245 detail::mvacld_part1(1, st, MU, Pall, Ljkall, lamall);
246 lamChain[K - 1] = lamall[K][0];
247 for (std::size_t j = 0; j < J; ++j) Lchain(j, K - 1) = Ljkall[K](j, 0);
250 for (std::size_t j = 0; j < J1; ++j)
251 for (std::size_t n = 0; n <= K; ++n) res.
pij(ldIdx[j], n) = Pall[K](j, n);
254 const long lmaxK = std::min(
static_cast<long>(K) - 1,
static_cast<long>(K - S));
255 if (D >= 2 && lmaxK >=
static_cast<long>(K - D + 1)) {
256 std::vector<Matrix<T>> L2prev(K + 1), L2cur(K + 1);
257 for (std::size_t k = K - D + 2; k <= K; ++k) {
258 const std::size_t t = K - k;
260 const long lhi = std::min(
static_cast<long>(k) - 1,
static_cast<long>(K - S));
261 for (
long l =
static_cast<long>(K - D + 1); l <= lhi; ++l) {
263 for (std::size_t vloc = 0; vloc < st.cnt[t]; ++vloc) {
264 const std::size_t vi = st.off[t] + vloc;
265 for (std::size_t j = 0; j < J; ++j) {
266 const long sj = st.succ(vi, j);
268 throw NumericError(
"pfqn_mvacld: multiplicity vector out of range");
269 const std::size_t sloc =
static_cast<std::size_t
>(sj) - st.off[t + 1];
271 (l ==
static_cast<long>(k) - 1) ? Ljkall[k - 1] : L2prev[l];
272 for (std::size_t i = 0; i < J; ++i)
273 acc(i, vloc) += Ljkall[k](j, vloc) * prev(i, sloc);
279 for (
long l =
static_cast<long>(K - D + 1); l <= lmaxK; ++l) {
280 const std::size_t l0 =
static_cast<std::size_t
>(l) - 1;
281 for (std::size_t j = 0; j < J; ++j) Lchain(j, l0) = L2cur[l](j, 0);
283 for (std::size_t j = J1; j < J; ++j)
284 if (st.a(j, l0) > zero) {
288 if (jIS == J)
throw NumericError(
"pfqn_mvacld: chain has no IS center");
289 lamChain[l0] = Lchain(jIS, l0) / st.a(jIS, l0);
297 std::vector<std::size_t>
perm(K);
298 for (std::size_t k = 0; k < K; ++k)
perm[k] = k;
299 for (std::size_t l = 1; l + 1 <= S; ++l) {
300 std::swap(
perm[K - l - 1],
perm[K - 1]);
301 for (std::size_t j = 0; j < J; ++j) {
302 const T tmp = st.a(j, K - l - 1);
303 st.a(j, K - l - 1) = st.a(j, K - 1);
304 st.a(j, K - 1) = tmp;
306 detail::mvacld_part1(K - l, st, MU, Pall, Ljkall, lamall);
307 lamChain[
perm[K - 1]] = lamall[K][0];
308 for (std::size_t j = 0; j < J; ++j) Lchain(j,
perm[K - 1]) = Ljkall[K](j, 0);
312 for (std::size_t g = 0; g < D; ++g) {
313 const std::size_t kg = K - D + g;
314 for (std::size_t p = 0; p < st.posr.size(); ++p) {
315 if (st.grpOfClass[p] != st.gorder[g])
continue;
316 const std::size_t r = st.posr[p];
318 res.
X[r] = nr * lamChain[kg];
319 for (std::size_t j = 0; j < J1; ++j) res.
Q(ldIdx[j], r) = nr * Lchain(j, kg);
322 for (std::size_t i = 0; i < M; ++i) res.
U[i] = one - res.
pij(i, 0);
323 for (std::size_t p = 0; p < st.posr.size(); ++p) {
324 const std::size_t r = st.posr[p];
325 if (res.
X[r] <= zero)
throw NumericError(
"pfqn_mvacld: nonpositive throughput");
327 for (std::size_t i = 0; i < Z.
rows(); ++i) zr += Z(i, r);