125 "solver_ncld: the load-dependent normalizing-constant analyzer forms "
126 "X = exp(lG(N-1_c) - lG(N)) and needs transcendental arithmetic; this backend has "
132 const std::size_t M =
sn.nstations, K =
sn.nclasses, C =
sn.nchains;
134 std::vector<double> nservers(M, 1.0);
135 std::vector<bool> isFCFS(M,
false);
136 bool anyFCFS =
false, anyMulti =
false;
137 for (std::size_t i = 0; i < M; ++i) {
138 nservers[i] =
sn.stations[i].nservers;
139 isFCFS[i] =
sn.stations[i].sched == SchedStrategy::FCFS;
140 if (isFCFS[i]) anyFCFS =
true;
141 if (std::isfinite(nservers[i]) && nservers[i] > 1.0) anyMulti =
true;
145 bool allClosed =
true;
152 const std::size_t Nt =
static_cast<std::size_t
>(
153 std::max<double>(1.0, std::ceil(std::isfinite(Ntot_d) ? Ntot_d : 1.0)));
163 for (std::size_t i = 0; i < M; ++i)
164 if (
static_cast<bool>(
sn.stations[i].cdscaling) ||
165 static_cast<bool>(
sn.stations[i].jdscaling))
169 for (std::size_t i = 0; i < M; ++i)
170 if (!
sn.stations[i].lldscaling.empty()) anyLld =
true;
173 if (!anyLld && M == 2 && allClosed) {
176 for (std::size_t i = 0; i < M; ++i) {
177 std::vector<T> lld(Nt, one);
178 for (std::size_t n = 1; n <= Nt; ++n)
180 std::min<double>(
static_cast<double>(n), nservers[i]));
181 sn.stations[i].lldscaling = lld;
184 }
else if (!detail::lld_encodes_multiserver(
sn)) {
186 "solver_ncld: the load-dependent solver does not support multi-server "
187 "stations unless they are expressed as limited load dependence mu(n) = "
197 std::size_t Wlld = Nt;
198 for (std::size_t i = 0; i < M; ++i)
199 Wlld = std::max(Wlld,
sn.stations[i].lldscaling.size());
201 for (std::size_t i = 0; i < M; ++i) {
202 const std::vector<T>& lld =
sn.stations[i].lldscaling;
203 if (lld.empty())
continue;
204 for (std::size_t n = 0; n < Wlld; ++n) lldscaling(i, n) = n < lld.size() ? lld[n] : lld.back();
211 for (std::size_t i = 0; i < M; ++i)
212 for (std::size_t k = 0; k < K; ++k)
213 if (
sn.disabled[i][k])
217 const std::vector<double> Nchain = detail::chain_population(
sn);
218 std::vector<std::size_t> openChains, closedChains;
219 for (std::size_t c = 0; c < C; ++c)
220 (std::isinf(Nchain[c]) ? openChains : closedChains).push_back(c);
221 std::vector<int> Nnc = detail::nc_population(Nchain);
223 for (std::size_t c : closedChains) Ncl +=
static_cast<std::size_t
>(Nnc[c]);
230 const std::string& pmethod =
opt.method;
239 std::vector<T> gamma(M, zero), nserv_t(M, one);
240 for (std::size_t i = 0; i < M; ++i) nserv_t[i] = num_traits<T>::from_double(nservers[i]);
241 std::vector<T> eta(M, one), eta_1(M, zero);
242 const int iter_max = anyFCFS ?
opt.iter_max : 1;
245 std::string actualmethod =
opt.method;
247 std::vector<T> Xchain(C, zero);
249 while (it < iter_max) {
252 for (std::size_t i = 0; i < M; ++i) {
255 if (!(v <= dev)) dev = v;
257 if (!(dev >
opt.iter_tol))
break;
263 for (std::size_t c = 0; c < C; ++c) {
264 const bool open = std::isinf(Nchain[c]);
265 const std::size_t rst =
sn.classes[
sn.inchain[c][0] - 1].refstat;
266 for (std::size_t i = 0; i < M; ++i) {
268 for (std::size_t k :
sn.inchain[c]) st += ST(i, k - 1) * d.
alpha(i, k - 1);
270 if (open && i + 1 == rst) {
274 for (std::size_t k :
sn.inchain[c])
275 if (!
sn.disabled[i][k - 1] &&
284 for (std::size_t i = 0; i < M; ++i)
285 for (std::size_t c = 0; c < C; ++c) {
292 std::vector<T> lambda(C, zero);
293 for (std::size_t c : openChains) {
294 const std::size_t rst =
sn.classes[
sn.inchain[c][0] - 1].refstat;
295 if (d.
STchain(rst - 1, c) > zero) lambda[c] = T(one / d.
STchain(rst - 1, c));
298 Matrix<T> L(M, C, zero), Z(M, C, zero), mu(M, Nt, one);
299 std::vector<std::size_t> infServers;
300 for (std::size_t i = 0; i < M; ++i) {
301 for (std::size_t c = 0; c < C; ++c) L(i, c) = d.
Lchain(i, c);
302 if (std::isinf(nservers[i])) {
303 infServers.push_back(i);
304 for (std::size_t c = 0; c < C; ++c) Z(i, c) = d.
Lchain(i, c);
305 for (std::size_t n = 1; n <= Nt; ++n)
308 for (std::size_t n = 0; n < Nt; ++n) mu(i, n) = lldscaling(i, n);
313 Xchain.assign(C, zero);
315 if (!openChains.empty()) {
322 std::vector<bool> isSource(M,
false), isDelay(M,
false);
323 for (std::size_t c : openChains)
324 isSource[
sn.classes[
sn.inchain[c][0] - 1].refstat - 1] =
true;
325 for (std::size_t i : infServers)
326 if (!isSource[i]) isDelay[i] =
true;
327 std::vector<std::size_t> queueStations;
328 for (std::size_t i = 0; i < M; ++i)
329 if (!isSource[i] && !isDelay[i]) queueStations.push_back(i);
330 const std::size_t nq = queueStations.size();
333 for (std::size_t i = 0; i < M; ++i)
335 for (std::size_t c = 0; c < C; ++c) Zvec(0, c) += d.
Lchain(i, c);
344 std::size_t ncol = std::max<std::size_t>(1, Ncl);
345 for (std::size_t qi = 0; qi < nq; ++qi)
346 ncol = std::max(ncol, detail::lld_saturation_level(lldscaling, queueStations[qi]));
347 Matrix<T> Dq(nq, C, zero), muq(nq, ncol, one);
348 const std::size_t Wq = lldscaling.
cols();
349 for (std::size_t qi = 0; qi < nq; ++qi) {
350 for (std::size_t c = 0; c < C; ++c) Dq(qi, c) = d.
Lchain(queueStations[qi], c);
351 for (std::size_t n = 0; n < ncol; ++n)
352 muq(qi, n) = lldscaling(queueStations[qi], n < Wq ? n : Wq - 1);
354 std::vector<int> Nmx(C, 0);
355 for (std::size_t c = 0; c < C; ++c)
361 for (std::size_t qi = 0; qi < nq; ++qi)
362 for (std::size_t c = 0; c < C; ++c) Qchain(queueStations[qi], c) = mx.
QN(qi, c);
363 for (std::size_t i = 0; i < M; ++i)
365 for (std::size_t c = 0; c < C; ++c)
366 Qchain(i, c) = T(d.
Lchain(i, c) * Xchain[c]);
367 actualmethod =
"ncldmx";
373 actualmethod = base.
method;
375 const bool repairman = (M == 2 && !infServers.empty());
376 std::size_t firstDelay = infServers.empty() ? 0 : infServers[0];
377 for (std::size_t r = 0; r < C; ++r) {
378 const std::vector<int> Nr = detail::oner(Nnc, r);
379 const double lGr =
pfqn::pfqn_ncld(L, Nr, Zzero, mu, pmethod, atol, nopt).lG;
382 const T qd = T(d.
Lchain(firstDelay, r) * Xchain[r]);
383 Qchain(firstDelay, r) = qd;
384 for (std::size_t i = 0; i < M; ++i)
389 std::size_t nfinite = 0;
390 for (std::size_t i = 0; i < M; ++i)
391 if (std::isfinite(nservers[i])) ++nfinite;
392 for (std::size_t i = 0; i < M; ++i) {
393 if (!(d.
Lchain(i, r) > zero))
continue;
394 if (std::isinf(nservers[i])) {
395 Qchain(i, r) = T(d.
Lchain(i, r) * Xchain[r]);
398 if (i + 1 == M && nfinite == 1) {
402 for (std::size_t i2 : infServers) acc += d.
Lchain(i2, r);
404 for (std::size_t i2 = 0; i2 + 1 < M; ++i2)
405 if (std::isfinite(nservers[i2])) q -= Qchain(i2, r);
406 Qchain(i, r) = q < zero ? zero : q;
414 for (std::size_t n = 0; n < muhati.
cols(); ++n) muhati_row(0, n) = muhati(i, n);
416 Matrix<T> Lhat(M + 1, C, zero), muhat(M + 1, muhati.
cols(), zero);
417 for (std::size_t i2 = 0; i2 < M; ++i2) {
418 for (std::size_t c = 0; c < C; ++c) Lhat(i2, c) = L(i2, c);
419 for (std::size_t n = 0; n < muhati.
cols(); ++n)
420 muhat(i2, n) = muhati(i2, n);
422 for (std::size_t c = 0; c < C; ++c) Lhat(M, c) = L(i, c);
423 for (std::size_t n = 0; n < fnc.
mu.cols(); ++n) muhat(M, n) = fnc.
mu(0, n);
424 Matrix<T> Lms_i(M - 1, C, zero), mu_i(M - 1, mu.
cols(), zero);
426 for (std::size_t i2 = 0; i2 < M; ++i2) {
427 if (i2 == i)
continue;
428 for (std::size_t c = 0; c < C; ++c) Lms_i(row, c) = L(i2, c);
429 for (std::size_t n = 0; n < mu.
cols(); ++n) mu_i(row, n) = mu(i2, n);
432 const double lGhat_fnci =
434 const double lGhatir =
438 const double dlGa = lGhat_fnci - lGhatir;
439 const double dlG_i = lGr_i - lGhatir;
446 Xchain[r] * (one + CQ));
451 Matrix<T> Rchain(M, C, zero), Tchain(M, C, zero);
452 for (std::size_t i = 0; i < M; ++i)
453 for (std::size_t c = 0; c < C; ++c) {
454 if (Xchain[c] != zero && d.
Vchain(i, c) != zero)
455 Rchain(i, c) = T(Qchain(i, c) / Xchain[c] / d.
Vchain(i, c));
456 Tchain(i, c) = T(Xchain[c] * d.
Vchain(i, c));
458 for (std::size_t i : infServers)
459 for (std::size_t c = 0; c < C; ++c)
462 for (std::size_t c = 0; c < C; ++c) {
463 if (Nnc[c] != 0)
continue;
465 for (std::size_t i = 0; i < M; ++i) {
471 for (std::size_t i = 0; i < M; ++i)
472 for (std::size_t c = 0; c < C; ++c) {
483 opt.highvar, isFCFS,
sn.rates, ST0, V, SCVnan, cls.
Tp, cls.
U, gamma, nserv_t);
490 std::vector<T> X = cls.
X;
492 for (std::size_t i = 0; i < A.rows(); ++i)
493 for (std::size_t j = 0; j < A.cols(); ++j)
494 if (A(i, j) < zero) A(i, j) = T(-A(i, j));
500 if (x < zero) x = T(-x);
505 for (std::size_t i = 0; i < M; ++i) {
506 const bool multi = std::isfinite(nservers[i]) && nservers[i] > 1.0;
507 if (multi || std::isinf(nservers[i])) {
508 const double div = multi ? nservers[i] : 1.0;
509 for (std::size_t k = 0; k < K; ++k) {
511 for (std::size_t cc = 0; cc < C; ++cc)
512 if (
sn.chains[cc][k]) c = cc;
513 if (c == C)
continue;
514 const std::size_t rs =
sn.classes[k].refstat;
515 const T vref =
sn.visits[c](
sn.stateful_of_station(rs) - 1, k);
516 if (vref == zero)
continue;
517 const T vi =
sn.visits[c](
sn.stateful_of_station(i + 1) - 1, k);
518 const bool open = std::isinf(
sn.classes[k].population);
522 const std::size_t src =
sn.classes[k].refstat;
523 if (!
sn.disabled[src - 1][k]) rate =
sn.rates(src - 1, k);
527 if (!(rate > zero))
continue;
541 const std::vector<T>& lldrow =
sn.stations[i].lldscaling;
542 if (lldrow.empty()) {
543 for (std::size_t n = 0; n < Nt; ++n)
544 if (lldscaling(i, n) > mx) mx = lldscaling(i, n);
546 for (std::size_t n = 0; n < lldrow.size(); ++n)
547 if (lldrow[n] > mx) mx = lldrow[n];
550 for (std::size_t k = 0; k < K; ++k) U(i, k) = T(U(i, k) / mx);
552 for (std::size_t k = 0; k < K; ++k) s += U(i, k);
554 for (std::size_t k = 0; k < K; ++k) U(i, k) = T(U(i, k) / s);
558 auto clear_nonfinite = [&](
Matrix<T>& A) {
559 for (std::size_t i = 0; i < A.rows(); ++i)
560 for (std::size_t j = 0; j < A.cols(); ++j)
569 for (std::size_t c = 0; c < C; ++c) {
570 if (std::isinf(Nchain[c]))
continue;
572 for (std::size_t k :
sn.inchain[c])
573 for (std::size_t i = 0; i < M; ++i) qden += Q(i, k - 1);
576 for (std::size_t k :
sn.inchain[c]) {
577 X[k - 1] = T(ratio * X[k - 1]);
578 for (std::size_t i = 0; i < M; ++i) {
579 Q(i, k - 1) = T(ratio * Q(i, k - 1));
580 Tp(i, k - 1) = T(ratio * Tp(i, k - 1));
581 U(i, k - 1) = T(ratio * U(i, k - 1));
582 R(i, k - 1) = Tp(i, k - 1) == zero ? zero : T(Q(i, k - 1) / Tp(i, k - 1));
592 out.
sol.C.assign(K, zero);
593 for (std::size_t k = 0; k < K; ++k) {
594 const double njobs =
sn.classes[k].population;
595 out.
sol.C[k] = (std::isfinite(njobs) && X[k] != zero)
601 out.
sol.method = actualmethod;