232 const std::vector<T>& Z,
const Matrix<T>& mu,
int terms) {
234 "pfqn_panaceald requires transcendental arithmetic (asymptotic expansion of "
235 "log G through the phi(n) transform)");
238 const std::size_t M = L.
rows(), R = L.
cols();
239 if (N.size() != R)
throw InputError(
"pfqn_panaceald: L and N disagree on the class count");
240 if (terms < 1 || terms > 3)
242 "pfqn_panaceald: the terms parameter must be 1, 2 or 3 (higher-order coefficients are "
245 std::vector<T> Zv = Z;
246 if (Zv.empty()) Zv.assign(R, zero);
247 if (Zv.size() != R)
throw InputError(
"pfqn_panaceald: Z has the wrong length");
254 const auto decline = [&](
const char* why) {
263 for (std::size_t r = 0; r < R; ++r) {
264 if (N[r] < 0)
throw InputError(
"pfqn_panaceald: negative population");
272 const std::size_t Nt =
static_cast<std::size_t
>(Ntl);
278 throw InputError(
"pfqn_panaceald: mu and L disagree on the station count");
279 if (mu.
cols() == 0)
throw InputError(
"pfqn_panaceald: mu has no rate column");
280 for (std::size_t i = 0; i < M; ++i)
281 for (std::size_t k = 0; k < Nt; ++k)
282 mux(i, k) = mu(i, k < mu.
cols() ? k : mu.
cols() - 1);
286 const double fineTol = 1e-8;
287 std::vector<bool> isIS(M,
false);
288 for (std::size_t i = 0; i < M; ++i) {
290 for (std::size_t k = 0; k < Nt && all; ++k)
297 std::vector<T> Ztot = Zv;
298 std::vector<std::size_t> qrows;
299 for (std::size_t i = 0; i < M; ++i) {
301 for (std::size_t r = 0; r < R; ++r) Ztot[r] += L(i, r);
306 const std::size_t Mq = qrows.size();
308 for (std::size_t r = 0; r < R; ++r)
309 if (N[r] > 0 && !(Ztot[r] > zero))
314 "a populated class visits no infinite server, so the expansion parameter rho_j0 "
317 const auto delay_only = [&]() {
319 for (std::size_t r = 0; r < R; ++r) {
321 lG -= detail::num_factln<T>(nT);
322 lG += detail::pald_xlogy(nT, Ztot[r]);
328 if (Mq == 0)
return delay_only();
331 for (std::size_t a = 0; a < Mq; ++a) {
332 for (std::size_t r = 0; r < R; ++r) Lq(a, r) = L(qrows[a], r);
333 for (std::size_t k = 0; k < Nt; ++k) muq(a, k) = mux(qrows[a], k);
335 for (std::size_t a = 0; a < Mq; ++a)
336 for (std::size_t k = 0; k < Nt; ++k) {
338 if (!(v > 0.0) || !std::isfinite(v))
339 return decline(
"a load-dependent rate is not positive and finite");
344 for (std::size_t a = 0; a < Mq; ++a)
345 for (std::size_t j = 0; j < R; ++j)
346 if (Ztot[j] > zero) r(a, j) = T(Lq(a, j) / Ztot[j]);
347 std::vector<T> lambda(Mq, zero), muK(Mq, one), alpha(Mq, one);
348 for (std::size_t a = 0; a < Mq; ++a) {
352 muK[a] = muq(a, Nt - 1);
353 alpha[a] = T(one - lambda[a] / muK[a]);
354 if (!(alpha[a] > zero))
356 "the model is not in normal usage (1 - lambda_i/mu_i(Ntot) <= 0 at some queueing "
357 "centre), so the {phi(n)} series diverges");
361 std::vector<std::vector<T> > lPi(Mq, std::vector<T>(Nt + 1, zero));
362 for (std::size_t a = 0; a < Mq; ++a)
363 for (std::size_t s = 1; s <= Nt; ++s) lPi[a][s] = T(lPi[a][s - 1] + log(muq(a, s - 1)));
365 const std::size_t nmax =
static_cast<std::size_t
>(2 * (terms - 1));
367 for (std::size_t a = 0; a < Mq; ++a)
368 for (std::size_t n = 0; n <= nmax; ++n)
369 lpsi(a, n) = detail::pald_logpsi(n, lambda[a], lPi[a], muK[a], alpha[a], Nt);
373 Matrix<T> mups(Mq, nmax > 0 ? nmax : 1, one);
374 for (std::size_t a = 0; a < Mq; ++a)
375 for (std::size_t n = 1; n <= nmax; ++n)
377 lpsi(a, n - 1) - lpsi(a, n)));
382 std::vector<T> A(3, zero);
385 for (std::size_t j = 0; j < R; ++j) {
386 std::vector<int> m(R, 0);
392 for (std::size_t j = 0; j < R; ++j) {
393 std::vector<int> m(R, 0);
396 detail::pald_pseudonet(r, m, mups);
401 detail::pald_pseudonet(r, m, mups);
402 for (std::size_t k = 0; k < R; ++k) {
403 if (k == j)
continue;
413 for (
int t = 0; t < terms; ++t) I += A[t];
415 return decline(
"the truncated normal-usage series is not positive, so its logarithm is "
419 for (std::size_t j = 0; j < R; ++j) {
421 lG -= detail::num_factln<T>(nT);
422 lG += detail::pald_xlogy(nT, Ztot[j]);
424 for (std::size_t a = 0; a < Mq; ++a) lG += lpsi(a, 0);
427 return decline(
"the expansion evaluated to a non-finite logarithm");