149 "solver_nc: the normalizing-constant analyzer forms X = exp(lG(N-1_c) - lG(N)) and "
150 "needs transcendental arithmetic; this backend has none");
160 const std::size_t M =
sn.nstations, K =
sn.nclasses, C =
sn.nchains;
162 std::vector<double> nservers(M, 1.0);
163 std::vector<bool> isFCFS(M,
false);
164 bool anyFCFS =
false;
165 for (std::size_t i = 0; i < M; ++i) {
166 nservers[i] =
sn.stations[i].nservers;
167 isFCFS[i] =
sn.stations[i].sched == SchedStrategy::FCFS;
168 if (isFCFS[i]) anyFCFS =
true;
174 std::vector<std::size_t> lcfsStat, lcfsprStat;
175 for (std::size_t i = 0; i < M; ++i) {
176 if (
sn.stations[i].sched == SchedStrategy::LCFS) lcfsStat.push_back(i + 1);
177 if (
sn.stations[i].sched == SchedStrategy::LCFSPR) lcfsprStat.push_back(i + 1);
179 if (!lcfsStat.empty() && !lcfsprStat.empty()) {
180 if (lcfsStat.size() != 1 || lcfsprStat.size() != 1)
182 "solver_nc: LCFS NC requires exactly one LCFS and one LCFS-PR station");
183 for (std::size_t c = 0; c < C; ++c) {
185 for (std::size_t r :
sn.inchain[c]) nc_pop +=
sn.classes[r - 1].population;
186 if (std::isinf(nc_pop))
188 "solver_nc: LCFS NC requires a closed queueing network");
192 for (std::size_t i : {lcfsStat[0], lcfsprStat[0]}) {
193 const std::size_t sf =
sn.stateful_of_station(i) - 1;
194 for (std::size_t r = 0; r < K; ++r)
195 if (
sn.rt(sf * K + r, sf * K + r) > zero)
197 "solver_nc: LCFS NC does not support self-loops at stations");
203 for (std::size_t i = 0; i < M; ++i)
204 for (std::size_t r = 0; r < K; ++r) {
206 if (std::isnan(mu))
continue;
207 out.
STeff(i, r) = mu == 0.0
209 std::numeric_limits<double>::infinity())
210 : T(one /
sn.rates(i, r));
214 if (!lcfsStat.empty())
216 "solver_nc: LCFS scheduling requires a paired LCFS-PR station");
218 const std::vector<double> Nchain = detail::chain_population(
sn);
219 const std::vector<int> Nnc = detail::nc_population(Nchain);
220 std::vector<std::size_t> openChains, closedChains;
221 for (std::size_t c = 0; c < C; ++c)
222 (std::isinf(Nchain[c]) ? openChains : closedChains).push_back(c);
244 for (std::size_t i = 0; i < M; ++i)
245 for (std::size_t k = 0; k < K; ++k)
246 if (
sn.disabled[i][k])
248 std::numeric_limits<double>::quiet_NaN());
250 std::vector<T> gamma(M, zero);
251 std::vector<T> nserv_t(M, one);
252 for (std::size_t i = 0; i < M; ++i) nserv_t[i] = num_traits<T>::from_double(nservers[i]);
254 std::vector<T> lambda(C, zero);
255 std::vector<T> eta(M, one), eta_1(M, zero);
256 const int iter_max = anyFCFS ?
opt.iter_max : 1;
259 std::string actualmethod =
opt.method;
262 while (it < iter_max) {
265 for (std::size_t i = 0; i < M; ++i) {
268 const double v = std::fabs(1.0 - e / e1);
269 if (!(v <= dev)) dev = v;
271 if (!(dev >
opt.iter_tol))
break;
279 for (std::size_t c = 0; c < C; ++c) {
280 if (!std::isinf(Nchain[c]))
continue;
281 const std::size_t rst =
sn.classes[
sn.inchain[c][0] - 1].refstat;
282 if (d.
STchain(rst - 1, c) != zero)
283 lambda[c] = T(one / d.
STchain(rst - 1, c));
286 for (std::size_t c = 0; c < C; ++c)
287 for (std::size_t i = 0; i < M; ++i) {
289 for (std::size_t k :
sn.inchain[c]) st += ST(i, k - 1) * d.
alpha(i, k - 1);
294 for (std::size_t i = 0; i < M; ++i)
295 for (std::size_t c = 0; c < C; ++c) {
304 Matrix<T> Lms(M, C, zero), Z(M, C, zero), Zms(M, C, zero);
305 std::vector<std::size_t> infServers;
306 for (std::size_t i = 0; i < M; ++i) {
307 if (std::isinf(nservers[i])) {
308 infServers.push_back(i);
309 for (std::size_t c = 0; c < C; ++c) Z(i, c) = d.
Lchain(i, c);
312 for (std::size_t c = 0; c < C; ++c) {
313 Lms(i, c) = T(d.
Lchain(i, c) / cs);
314 Zms(i, c) = T(d.
Lchain(i, c) *
320 for (std::size_t c = 0; c < C; ++c)
321 for (std::size_t i = 0; i < M; ++i) Ztot(0, c) += Z(i, c) + Zms(i, c);
337 out.
sol.X.assign(K, zero);
338 out.
sol.C.assign(K, zero);
341 out.
sol.method =
opt.method;
347 actualmethod = base.
method;
348 std::vector<T> Xchain = base.
X;
359 for (std::size_t c = 0; c < C; ++c) {
361 for (std::size_t i = 0; i < M; ++i) s += Zms(i, c);
369 if (Xchain.empty()) {
372 for (std::size_t r : closedChains) {
373 const std::vector<int> Nr = detail::oner(Nnc, r);
383 out.
sol.X.assign(K, zero);
384 out.
sol.C.assign(K, zero);
387 out.
sol.method =
opt.method;
392 const double lGr = sub.lG;
394 for (std::size_t i = 0; i < M; ++i) {
395 if (!(d.
Lchain(i, r) > zero))
continue;
396 if (std::isinf(nservers[i])) {
397 Qchain(i, r) = T(d.
Lchain(i, r) * Xchain[r]);
404 for (std::size_t i2 = 0; i2 < M; ++i2) {
405 if (i2 == i)
continue;
406 for (std::size_t c = 0; c < C; ++c) Lar(row, c) = Lms(i2, c);
409 for (std::size_t c = 0; c < C; ++c) Lar(row, c) = Lms(i, c);
411 std::vector<T> lam_ar = lambda;
412 lam_ar.push_back(zero);
413 std::vector<int> N_ar = Nr;
416 for (std::size_t c = 0; c < C; ++c) Z_ar(0, c) = Ztot(0, c);
422 Qchain(i, r) = T(Zms(i, r) * Xchain[r] +
424 std::exp(ar.
lG - lG)));
427 for (std::size_t i = 0; i < M; ++i)
428 for (std::size_t c = 0; c < C; ++c)
433 for (std::size_t r : openChains)
434 for (std::size_t i = 0; i < M; ++i) {
436 for (std::size_t o : openChains) load += lambda[o] * d.
Lchain(i, o);
442 if (closedChains.empty() && std::isfinite(nservers[i]) && nservers[i] > 1.0) {
443 if (load > zero && d.
Lchain(i, r) > zero) {
444 const T W =
qsys::qsys_mmk(load, one,
static_cast<unsigned>(nservers[i])).W;
445 Qchain(i, r) = T(W * load * lambda[r] * d.
Lchain(i, r) / load);
452 std::isinf(nservers[i])
455 if (den == zero)
continue;
457 for (std::size_t cc : closedChains) qc += Qchain(i, cc);
458 Qchain(i, r) = T(lambda[r] * d.
Lchain(i, r) / den * (one + qc));
469 for (std::size_t c = 0; c < C; ++c)
470 for (std::size_t i = 0; i < M; ++i) {
471 if (!(d.
Lchain(i, c) > zero))
continue;
472 if (std::isinf(nservers[i]))
473 Qchain(i, c) = T(d.
Lchain(i, c) * Xchain[c]);
474 else if (nservers[i] > 1.0)
475 Qchain(i, c) = T(Qchain(i, c) + Zms(i, c) * Xchain[c]);
479 Matrix<T> Rchain(M, C, zero), Tchain(M, C, zero);
480 for (std::size_t i = 0; i < M; ++i)
481 for (std::size_t c = 0; c < C; ++c) {
482 if (Xchain[c] != zero && d.
Vchain(i, c) != zero)
483 Rchain(i, c) = T(Qchain(i, c) / Xchain[c] / d.
Vchain(i, c));
484 Tchain(i, c) = T(Xchain[c] * d.
Vchain(i, c));
486 for (std::size_t i : infServers)
487 for (std::size_t c = 0; c < C; ++c)
488 Rchain(i, c) = d.
Vchain(i, c) == zero
498 opt.highvar, isFCFS,
sn.rates, ST0, V, SCVnan, cls.
Tp, cls.
U, gamma, nserv_t);
506 "solver_nc: the analyzer made no pass; iter_max must be at least one");
509 std::vector<T> X = cls.
X;
511 for (std::size_t i = 0; i < A.rows(); ++i)
512 for (std::size_t j = 0; j < A.cols(); ++j) {
513 if (A(i, j) < zero) A(i, j) = T(-A(i, j));
521 if (x < zero) x = T(-x);
528 for (std::size_t c = 0; c < C; ++c) {
529 if (std::isinf(Nchain[c]))
continue;
531 for (std::size_t k :
sn.inchain[c])
532 for (std::size_t i = 0; i < M; ++i) qden += Q(i, k - 1);
533 const T ratio = qden > zero
536 for (std::size_t k :
sn.inchain[c]) {
537 X[k - 1] = T(ratio * X[k - 1]);
538 for (std::size_t i = 0; i < M; ++i) {
539 Q(i, k - 1) = T(ratio * Q(i, k - 1));
540 Tp(i, k - 1) = T(ratio * Tp(i, k - 1));
541 U(i, k - 1) = T(ratio * U(i, k - 1));
542 R(i, k - 1) = Tp(i, k - 1) == zero ? zero : T(Q(i, k - 1) / Tp(i, k - 1));
552 out.
sol.C.assign(K, zero);
553 for (std::size_t k = 0; k < K; ++k) {
554 const double njobs =
sn.classes[k].population;
555 if (std::isfinite(njobs) && X[k] != zero)
558 out.
sol.C[k] = cls.
C[k];
562 out.
sol.method = actualmethod;