139 "solver_ncld: the load-dependent normalizing-constant analyzer forms "
140 "X = exp(lG(N-1_c) - lG(N)) and needs transcendental arithmetic; this backend has "
146 const std::size_t M =
sn.nstations, K =
sn.nclasses, C =
sn.nchains;
148 std::vector<double> nservers(M, 1.0);
149 std::vector<bool> isFCFS(M,
false);
150 bool anyFCFS =
false, anyMulti =
false;
151 for (std::size_t i = 0; i < M; ++i) {
152 nservers[i] =
sn.stations[i].nservers;
153 isFCFS[i] =
sn.stations[i].sched == SchedStrategy::FCFS;
154 if (isFCFS[i]) anyFCFS =
true;
155 if (std::isfinite(nservers[i]) && nservers[i] > 1.0) anyMulti =
true;
159 bool allClosed =
true;
166 const std::size_t Nt =
static_cast<std::size_t
>(
167 std::max<double>(1.0, std::ceil(std::isfinite(Ntot_d) ? Ntot_d : 1.0)));
174 for (std::size_t i = 0; i < M; ++i)
178 for (std::size_t i = 0; i < M; ++i)
179 if (!
sn.stations[i].lldscaling.empty()) anyLld =
true;
182 if (!anyLld && M == 2 && allClosed) {
185 for (std::size_t i = 0; i < M; ++i) {
186 std::vector<T> lld(Nt, one);
187 for (std::size_t n = 1; n <= Nt; ++n)
189 std::min<double>(
static_cast<double>(n), nservers[i]));
190 sn.stations[i].lldscaling = lld;
193 }
else if (!detail::lld_encodes_multiserver(
sn)) {
195 "solver_ncld: the load-dependent solver does not support multi-server "
196 "stations unless they are expressed as limited load dependence mu(n) = "
206 std::size_t Wlld = Nt;
207 for (std::size_t i = 0; i < M; ++i)
208 Wlld = std::max(Wlld,
sn.stations[i].lldscaling.size());
210 for (std::size_t i = 0; i < M; ++i) {
211 const std::vector<T>& lld =
sn.stations[i].lldscaling;
212 if (lld.empty())
continue;
213 for (std::size_t n = 0; n < Wlld; ++n) lldscaling(i, n) = n < lld.size() ? lld[n] : lld.back();
220 for (std::size_t i = 0; i < M; ++i)
221 for (std::size_t k = 0; k < K; ++k)
222 if (
sn.disabled[i][k])
226 const std::vector<double> Nchain = detail::chain_population(
sn);
227 std::vector<std::size_t> openChains, closedChains;
228 for (std::size_t c = 0; c < C; ++c)
229 (std::isinf(Nchain[c]) ? openChains : closedChains).push_back(c);
230 std::vector<int> Nnc = detail::nc_population(Nchain);
232 for (std::size_t c : closedChains) Ncl +=
static_cast<std::size_t
>(Nnc[c]);
243 std::vector<T> gamma(M, zero), nserv_t(M, one);
244 for (std::size_t i = 0; i < M; ++i) nserv_t[i] = num_traits<T>::from_double(nservers[i]);
245 std::vector<T> eta(M, one), eta_1(M, zero);
246 const int iter_max = anyFCFS ?
opt.iter_max : 1;
249 std::string actualmethod =
opt.method;
251 std::vector<T> Xchain(C, zero);
253 while (it < iter_max) {
256 for (std::size_t i = 0; i < M; ++i) {
259 if (!(v <= dev)) dev = v;
261 if (!(dev >
opt.iter_tol))
break;
267 for (std::size_t c = 0; c < C; ++c) {
268 const bool open = std::isinf(Nchain[c]);
269 const std::size_t rst =
sn.classes[
sn.inchain[c][0] - 1].refstat;
270 for (std::size_t i = 0; i < M; ++i) {
272 for (std::size_t k :
sn.inchain[c]) st += ST(i, k - 1) * d.
alpha(i, k - 1);
274 if (open && i + 1 == rst) {
278 for (std::size_t k :
sn.inchain[c])
279 if (!
sn.disabled[i][k - 1] &&
288 for (std::size_t i = 0; i < M; ++i)
289 for (std::size_t c = 0; c < C; ++c) {
296 std::vector<T> lambda(C, zero);
297 for (std::size_t c : openChains) {
298 const std::size_t rst =
sn.classes[
sn.inchain[c][0] - 1].refstat;
299 if (d.
STchain(rst - 1, c) > zero) lambda[c] = T(one / d.
STchain(rst - 1, c));
302 Matrix<T> L(M, C, zero), Z(M, C, zero), mu(M, Nt, one);
303 std::vector<std::size_t> infServers;
304 for (std::size_t i = 0; i < M; ++i) {
305 for (std::size_t c = 0; c < C; ++c) L(i, c) = d.
Lchain(i, c);
306 if (std::isinf(nservers[i])) {
307 infServers.push_back(i);
308 for (std::size_t c = 0; c < C; ++c) Z(i, c) = d.
Lchain(i, c);
309 for (std::size_t n = 1; n <= Nt; ++n)
312 for (std::size_t n = 0; n < Nt; ++n) mu(i, n) = lldscaling(i, n);
317 Xchain.assign(C, zero);
319 if (!openChains.empty()) {
326 std::vector<bool> isSource(M,
false), isDelay(M,
false);
327 for (std::size_t c : openChains)
328 isSource[
sn.classes[
sn.inchain[c][0] - 1].refstat - 1] =
true;
329 for (std::size_t i : infServers)
330 if (!isSource[i]) isDelay[i] =
true;
331 std::vector<std::size_t> queueStations;
332 for (std::size_t i = 0; i < M; ++i)
333 if (!isSource[i] && !isDelay[i]) queueStations.push_back(i);
334 const std::size_t nq = queueStations.size();
337 for (std::size_t i = 0; i < M; ++i)
339 for (std::size_t c = 0; c < C; ++c) Zvec(0, c) += d.
Lchain(i, c);
348 std::size_t ncol = std::max<std::size_t>(1, Ncl);
349 for (std::size_t qi = 0; qi < nq; ++qi)
350 ncol = std::max(ncol, detail::lld_saturation_level(lldscaling, queueStations[qi]));
351 Matrix<T> Dq(nq, C, zero), muq(nq, ncol, one);
352 const std::size_t Wq = lldscaling.
cols();
353 for (std::size_t qi = 0; qi < nq; ++qi) {
354 for (std::size_t c = 0; c < C; ++c) Dq(qi, c) = d.
Lchain(queueStations[qi], c);
355 for (std::size_t n = 0; n < ncol; ++n)
356 muq(qi, n) = lldscaling(queueStations[qi], n < Wq ? n : Wq - 1);
358 std::vector<int> Nmx(C, 0);
359 for (std::size_t c = 0; c < C; ++c)
365 for (std::size_t qi = 0; qi < nq; ++qi)
366 for (std::size_t c = 0; c < C; ++c) Qchain(queueStations[qi], c) = mx.
QN(qi, c);
367 for (std::size_t i = 0; i < M; ++i)
369 for (std::size_t c = 0; c < C; ++c)
370 Qchain(i, c) = T(d.
Lchain(i, c) * Xchain[c]);
371 actualmethod =
"ncldmx";
377 actualmethod = base.
method;
379 const bool repairman = (M == 2 && !infServers.empty());
380 std::size_t firstDelay = infServers.empty() ? 0 : infServers[0];
381 for (std::size_t r = 0; r < C; ++r) {
382 const std::vector<int> Nr = detail::oner(Nnc, r);
383 const double lGr =
pfqn::pfqn_ncld(L, Nr, Zzero, mu, pmethod, atol, nopt).lG;
386 const T qd = T(d.
Lchain(firstDelay, r) * Xchain[r]);
387 Qchain(firstDelay, r) = qd;
388 for (std::size_t i = 0; i < M; ++i)
393 std::size_t nfinite = 0;
394 for (std::size_t i = 0; i < M; ++i)
395 if (std::isfinite(nservers[i])) ++nfinite;
396 for (std::size_t i = 0; i < M; ++i) {
397 if (!(d.
Lchain(i, r) > zero))
continue;
398 if (std::isinf(nservers[i])) {
399 Qchain(i, r) = T(d.
Lchain(i, r) * Xchain[r]);
402 if (i + 1 == M && nfinite == 1) {
406 for (std::size_t i2 : infServers) acc += d.
Lchain(i2, r);
408 for (std::size_t i2 = 0; i2 + 1 < M; ++i2)
409 if (std::isfinite(nservers[i2])) q -= Qchain(i2, r);
410 Qchain(i, r) = q < zero ? zero : q;
418 for (std::size_t n = 0; n < muhati.
cols(); ++n) muhati_row(0, n) = muhati(i, n);
420 Matrix<T> Lhat(M + 1, C, zero), muhat(M + 1, muhati.
cols(), zero);
421 for (std::size_t i2 = 0; i2 < M; ++i2) {
422 for (std::size_t c = 0; c < C; ++c) Lhat(i2, c) = L(i2, c);
423 for (std::size_t n = 0; n < muhati.
cols(); ++n)
424 muhat(i2, n) = muhati(i2, n);
426 for (std::size_t c = 0; c < C; ++c) Lhat(M, c) = L(i, c);
427 for (std::size_t n = 0; n < fnc.
mu.cols(); ++n) muhat(M, n) = fnc.
mu(0, n);
428 Matrix<T> Lms_i(M - 1, C, zero), mu_i(M - 1, mu.
cols(), zero);
430 for (std::size_t i2 = 0; i2 < M; ++i2) {
431 if (i2 == i)
continue;
432 for (std::size_t c = 0; c < C; ++c) Lms_i(row, c) = L(i2, c);
433 for (std::size_t n = 0; n < mu.
cols(); ++n) mu_i(row, n) = mu(i2, n);
436 const double lGhat_fnci =
438 const double lGhatir =
442 const double dlGa = lGhat_fnci - lGhatir;
443 const double dlG_i = lGr_i - lGhatir;
450 Xchain[r] * (one + CQ));
455 Matrix<T> Rchain(M, C, zero), Tchain(M, C, zero);
456 for (std::size_t i = 0; i < M; ++i)
457 for (std::size_t c = 0; c < C; ++c) {
458 if (Xchain[c] != zero && d.
Vchain(i, c) != zero)
459 Rchain(i, c) = T(Qchain(i, c) / Xchain[c] / d.
Vchain(i, c));
460 Tchain(i, c) = T(Xchain[c] * d.
Vchain(i, c));
462 for (std::size_t i : infServers)
463 for (std::size_t c = 0; c < C; ++c)
466 for (std::size_t c = 0; c < C; ++c) {
467 if (Nnc[c] != 0)
continue;
469 for (std::size_t i = 0; i < M; ++i) {
475 for (std::size_t i = 0; i < M; ++i)
476 for (std::size_t c = 0; c < C; ++c) {
487 opt.highvar, isFCFS,
sn.rates, ST0, V, SCVnan, cls.
Tp, cls.
U, gamma, nserv_t);
494 std::vector<T> X = cls.
X;
496 for (std::size_t i = 0; i < A.rows(); ++i)
497 for (std::size_t j = 0; j < A.cols(); ++j)
498 if (A(i, j) < zero) A(i, j) = T(-A(i, j));
504 if (x < zero) x = T(-x);
509 for (std::size_t i = 0; i < M; ++i) {
510 const bool multi = std::isfinite(nservers[i]) && nservers[i] > 1.0;
511 if (multi || std::isinf(nservers[i])) {
512 const double div = multi ? nservers[i] : 1.0;
513 for (std::size_t k = 0; k < K; ++k) {
515 for (std::size_t cc = 0; cc < C; ++cc)
516 if (
sn.chains[cc][k]) c = cc;
517 if (c == C)
continue;
518 const std::size_t rs =
sn.classes[k].refstat;
519 const T vref =
sn.visits[c](
sn.stateful_of_station(rs) - 1, k);
520 if (vref == zero)
continue;
521 const T vi =
sn.visits[c](
sn.stateful_of_station(i + 1) - 1, k);
522 const bool open = std::isinf(
sn.classes[k].population);
526 const std::size_t src =
sn.classes[k].refstat;
527 if (!
sn.disabled[src - 1][k]) rate =
sn.rates(src - 1, k);
531 if (!(rate > zero))
continue;
545 const std::vector<T>& lldrow =
sn.stations[i].lldscaling;
546 if (lldrow.empty()) {
547 for (std::size_t n = 0; n < Nt; ++n)
548 if (lldscaling(i, n) > mx) mx = lldscaling(i, n);
550 for (std::size_t n = 0; n < lldrow.size(); ++n)
551 if (lldrow[n] > mx) mx = lldrow[n];
554 for (std::size_t k = 0; k < K; ++k) U(i, k) = T(U(i, k) / mx);
556 for (std::size_t k = 0; k < K; ++k) s += U(i, k);
558 for (std::size_t k = 0; k < K; ++k) U(i, k) = T(U(i, k) / s);
562 auto clear_nonfinite = [&](
Matrix<T>& A) {
563 for (std::size_t i = 0; i < A.rows(); ++i)
564 for (std::size_t j = 0; j < A.cols(); ++j)
573 for (std::size_t c = 0; c < C; ++c) {
574 if (std::isinf(Nchain[c]))
continue;
576 for (std::size_t k :
sn.inchain[c])
577 for (std::size_t i = 0; i < M; ++i) qden += Q(i, k - 1);
580 for (std::size_t k :
sn.inchain[c]) {
581 X[k - 1] = T(ratio * X[k - 1]);
582 for (std::size_t i = 0; i < M; ++i) {
583 Q(i, k - 1) = T(ratio * Q(i, k - 1));
584 Tp(i, k - 1) = T(ratio * Tp(i, k - 1));
585 U(i, k - 1) = T(ratio * U(i, k - 1));
586 R(i, k - 1) = Tp(i, k - 1) == zero ? zero : T(Q(i, k - 1) / Tp(i, k - 1));
596 out.
sol.C.assign(K, zero);
597 for (std::size_t k = 0; k < K; ++k) {
598 const double njobs =
sn.classes[k].population;
599 out.
sol.C[k] = (std::isfinite(njobs) && X[k] != zero)
605 out.
sol.method = actualmethod;