197 const std::vector<T>& Z,
const std::vector<Servers>& mi,
200 "sum_closed requires transcendental arithmetic: it locates the root of the "
201 "population constraint by bisection to within tol, so its answer is inexact "
202 "whatever the arithmetic");
203 const std::size_t M = L.
rows(), R = L.
cols();
204 if (N.size() != R)
throw InputError(
"sum_closed: L and N disagree on the class count");
205 if (Z.size() != R)
throw InputError(
"sum_closed: L and Z disagree on the class count");
206 if (mi.size() != M)
throw InputError(
"sum_closed: L and mi disagree on the station count");
207 if (scv.
rows() != M || scv.
cols() != R)
throw InputError(
"sum_closed: scv has the wrong shape");
209 if (v < 0)
throw InputError(
"sum_closed: negative population");
214 out.
XN.assign(R, zero);
220 for (
long v : N) K += v;
221 if (K == 0)
return out;
225 T lambda_l = zero, lambda_u = zero;
227 for (std::size_t i = 0; i < M; ++i) {
228 if (L(i, 0) > zero) {
231 if (!ub_set || cand < lambda_u) {
239 if (!ub_set || cand < lambda_u) {
244 if (!ub_set)
throw InputError(
"sum_closed: all service demands are zero");
247 for (out.
it = 1; out.
it <= options.maxiter; ++out.
it) {
248 lambda = (lambda_l + lambda_u) / two;
249 std::vector<T> X(1, lambda);
250 const Matrix<T> Qir = detail::sum_node_qlen(L, X, mi, scv, K);
252 for (std::size_t i = 0; i < M; ++i) g += Qir(i, 0);
255 if (gap <= options.tol ||
263 if (out.
it > options.maxiter) out.
it = options.maxiter;
267 for (out.
it = 1; out.
it <= options.maxiter; ++out.
it) {
269 for (std::size_t r = 0; r < R; ++r) {
270 if (N[r] == 0)
continue;
273 for (std::size_t i = 0; i < M; ++i) {
274 if (!(L(i, r) > zero))
continue;
276 if (mi[i].infinite) {
280 for (std::size_t q = 0; q < R; ++q) rowload += out.
XN[q] * L(i, q);
282 if (rem < zero) rem = zero;
283 cand = rem / L(i, r);
285 if (!ub_set || cand < ub) {
292 if (!ub_set || cand < ub) {
297 if (!ub_set)
throw InputError(
"sum_closed: all service demands are zero");
299 const T lambda_old = out.
XN[r];
300 T lambda_l = zero, lambda_u = ub;
302 const double stop = options.tol * (ubd > 1.0 ? ubd : 1.0) / 1e3;
304 const T lambda = (lambda_l + lambda_u) / two;
306 const Matrix<T> Qir = detail::sum_node_qlen(L, out.
XN, mi, scv, K);
308 for (std::size_t i = 0; i < M; ++i) g += Qir(i, r);
314 out.
XN[r] = (lambda_l + lambda_u) / two;
316 if (d > delta) delta = d;
318 if (delta <= options.tol)
break;
320 if (out.
it > options.maxiter) out.
it = options.maxiter;
323 out.
QN = detail::sum_node_qlen(L, out.
XN, mi, scv, K);
324 for (std::size_t i = 0; i < M; ++i)
325 for (std::size_t r = 0; r < R; ++r) {
326 out.
UN(i, r) = mi[i].infinite
327 ? T(out.
XN[r] * L(i, r))
329 if (out.
XN[r] > zero) out.
RN(i, r) = out.
QN(i, r) / out.
XN[r];