148 "solver_nc: the normalizing-constant analyzer forms X = exp(lG(N-1_c) - lG(N)) and "
149 "needs transcendental arithmetic; this backend has none");
159 const std::size_t M =
sn.nstations, K =
sn.nclasses, C =
sn.nchains;
161 std::vector<double> nservers(M, 1.0);
162 std::vector<bool> isFCFS(M,
false);
163 bool anyFCFS =
false;
164 for (std::size_t i = 0; i < M; ++i) {
165 nservers[i] =
sn.stations[i].nservers;
166 isFCFS[i] =
sn.stations[i].sched == SchedStrategy::FCFS;
167 if (isFCFS[i]) anyFCFS =
true;
173 std::vector<std::size_t> lcfsStat, lcfsprStat;
174 for (std::size_t i = 0; i < M; ++i) {
175 if (
sn.stations[i].sched == SchedStrategy::LCFS) lcfsStat.push_back(i + 1);
176 if (
sn.stations[i].sched == SchedStrategy::LCFSPR) lcfsprStat.push_back(i + 1);
178 if (!lcfsStat.empty() && !lcfsprStat.empty()) {
179 if (lcfsStat.size() != 1 || lcfsprStat.size() != 1)
181 "solver_nc: LCFS NC requires exactly one LCFS and one LCFS-PR station");
182 for (std::size_t c = 0; c < C; ++c) {
184 for (std::size_t r :
sn.inchain[c]) nc_pop +=
sn.classes[r - 1].population;
185 if (std::isinf(nc_pop))
187 "solver_nc: LCFS NC requires a closed queueing network");
191 for (std::size_t i : {lcfsStat[0], lcfsprStat[0]}) {
192 const std::size_t sf =
sn.stateful_of_station(i) - 1;
193 for (std::size_t r = 0; r < K; ++r)
194 if (
sn.rt(sf * K + r, sf * K + r) > zero)
196 "solver_nc: LCFS NC does not support self-loops at stations");
202 for (std::size_t i = 0; i < M; ++i)
203 for (std::size_t r = 0; r < K; ++r) {
205 if (std::isnan(mu))
continue;
206 out.
STeff(i, r) = mu == 0.0
208 std::numeric_limits<double>::infinity())
209 : T(one /
sn.rates(i, r));
213 if (!lcfsStat.empty())
215 "solver_nc: LCFS scheduling requires a paired LCFS-PR station");
217 const std::vector<double> Nchain = detail::chain_population(
sn);
218 const std::vector<int> Nnc = detail::nc_population(Nchain);
219 std::vector<std::size_t> openChains, closedChains;
220 for (std::size_t c = 0; c < C; ++c)
221 (std::isinf(Nchain[c]) ? openChains : closedChains).push_back(c);
243 for (std::size_t i = 0; i < M; ++i)
244 for (std::size_t k = 0; k < K; ++k)
245 if (
sn.disabled[i][k])
247 std::numeric_limits<double>::quiet_NaN());
249 std::vector<T> gamma(M, zero);
250 std::vector<T> nserv_t(M, one);
251 for (std::size_t i = 0; i < M; ++i) nserv_t[i] = num_traits<T>::from_double(nservers[i]);
253 std::vector<T> lambda(C, zero);
254 std::vector<T> eta(M, one), eta_1(M, zero);
255 const int iter_max = anyFCFS ?
opt.iter_max : 1;
258 std::string actualmethod =
opt.method;
261 while (it < iter_max) {
264 for (std::size_t i = 0; i < M; ++i) {
267 const double v = std::fabs(1.0 - e / e1);
268 if (!(v <= dev)) dev = v;
270 if (!(dev >
opt.iter_tol))
break;
278 for (std::size_t c = 0; c < C; ++c) {
279 if (!std::isinf(Nchain[c]))
continue;
280 const std::size_t rst =
sn.classes[
sn.inchain[c][0] - 1].refstat;
281 if (d.
STchain(rst - 1, c) != zero)
282 lambda[c] = T(one / d.
STchain(rst - 1, c));
285 for (std::size_t c = 0; c < C; ++c)
286 for (std::size_t i = 0; i < M; ++i) {
288 for (std::size_t k :
sn.inchain[c]) st += ST(i, k - 1) * d.
alpha(i, k - 1);
293 for (std::size_t i = 0; i < M; ++i)
294 for (std::size_t c = 0; c < C; ++c) {
303 Matrix<T> Lms(M, C, zero), Z(M, C, zero), Zms(M, C, zero);
304 std::vector<std::size_t> infServers;
305 for (std::size_t i = 0; i < M; ++i) {
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);
311 for (std::size_t c = 0; c < C; ++c) {
312 Lms(i, c) = T(d.
Lchain(i, c) / cs);
313 Zms(i, c) = T(d.
Lchain(i, c) *
319 for (std::size_t c = 0; c < C; ++c)
320 for (std::size_t i = 0; i < M; ++i) Ztot(0, c) += Z(i, c) + Zms(i, c);
336 out.
sol.X.assign(K, zero);
337 out.
sol.C.assign(K, zero);
340 out.
sol.method =
opt.method;
346 actualmethod = base.
method;
347 std::vector<T> Xchain = base.
X;
358 for (std::size_t c = 0; c < C; ++c) {
360 for (std::size_t i = 0; i < M; ++i) s += Zms(i, c);
368 if (Xchain.empty()) {
371 for (std::size_t r : closedChains) {
372 const std::vector<int> Nr = detail::oner(Nnc, r);
382 out.
sol.X.assign(K, zero);
383 out.
sol.C.assign(K, zero);
386 out.
sol.method =
opt.method;
391 const double lGr = sub.lG;
393 for (std::size_t i = 0; i < M; ++i) {
394 if (!(d.
Lchain(i, r) > zero))
continue;
395 if (std::isinf(nservers[i])) {
396 Qchain(i, r) = T(d.
Lchain(i, r) * Xchain[r]);
403 for (std::size_t i2 = 0; i2 < M; ++i2) {
404 if (i2 == i)
continue;
405 for (std::size_t c = 0; c < C; ++c) Lar(row, c) = Lms(i2, c);
408 for (std::size_t c = 0; c < C; ++c) Lar(row, c) = Lms(i, c);
410 std::vector<T> lam_ar = lambda;
411 lam_ar.push_back(zero);
412 std::vector<int> N_ar = Nr;
415 for (std::size_t c = 0; c < C; ++c) Z_ar(0, c) = Ztot(0, c);
421 Qchain(i, r) = T(Zms(i, r) * Xchain[r] +
423 std::exp(ar.
lG - lG)));
426 for (std::size_t i = 0; i < M; ++i)
427 for (std::size_t c = 0; c < C; ++c)
432 for (std::size_t r : openChains)
433 for (std::size_t i = 0; i < M; ++i) {
435 for (std::size_t o : openChains) load += lambda[o] * d.
Lchain(i, o);
437 std::isinf(nservers[i])
440 if (den == zero)
continue;
442 for (std::size_t cc : closedChains) qc += Qchain(i, cc);
443 Qchain(i, r) = T(lambda[r] * d.
Lchain(i, r) / den * (one + qc));
454 for (std::size_t c = 0; c < C; ++c)
455 for (std::size_t i = 0; i < M; ++i) {
456 if (!(d.
Lchain(i, c) > zero))
continue;
457 if (std::isinf(nservers[i]))
458 Qchain(i, c) = T(d.
Lchain(i, c) * Xchain[c]);
459 else if (nservers[i] > 1.0)
460 Qchain(i, c) = T(Qchain(i, c) + Zms(i, c) * Xchain[c]);
464 Matrix<T> Rchain(M, C, zero), Tchain(M, C, zero);
465 for (std::size_t i = 0; i < M; ++i)
466 for (std::size_t c = 0; c < C; ++c) {
467 if (Xchain[c] != zero && d.
Vchain(i, c) != zero)
468 Rchain(i, c) = T(Qchain(i, c) / Xchain[c] / d.
Vchain(i, c));
469 Tchain(i, c) = T(Xchain[c] * d.
Vchain(i, c));
471 for (std::size_t i : infServers)
472 for (std::size_t c = 0; c < C; ++c)
473 Rchain(i, c) = d.
Vchain(i, c) == zero
483 opt.highvar, isFCFS,
sn.rates, ST0, V, SCVnan, cls.
Tp, cls.
U, gamma, nserv_t);
491 "solver_nc: the analyzer made no pass; iter_max must be at least one");
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));
506 if (x < zero) x = T(-x);
513 for (std::size_t c = 0; c < C; ++c) {
514 if (std::isinf(Nchain[c]))
continue;
516 for (std::size_t k :
sn.inchain[c])
517 for (std::size_t i = 0; i < M; ++i) qden += Q(i, k - 1);
518 const T ratio = qden > zero
521 for (std::size_t k :
sn.inchain[c]) {
522 X[k - 1] = T(ratio * X[k - 1]);
523 for (std::size_t i = 0; i < M; ++i) {
524 Q(i, k - 1) = T(ratio * Q(i, k - 1));
525 Tp(i, k - 1) = T(ratio * Tp(i, k - 1));
526 U(i, k - 1) = T(ratio * U(i, k - 1));
527 R(i, k - 1) = Tp(i, k - 1) == zero ? zero : T(Q(i, k - 1) / Tp(i, k - 1));
537 out.
sol.C.assign(K, zero);
538 for (std::size_t k = 0; k < K; ++k) {
539 const double njobs =
sn.classes[k].population;
540 if (std::isfinite(njobs) && X[k] != zero)
543 out.
sol.C[k] = cls.
C[k];
547 out.
sol.method = actualmethod;