184 const std::string& method,
const T& atol,
const NcOptions& nopt) {
185 const std::size_t M = D.
rows();
186 const std::size_t R = D.
cols();
187 if (N.size() != R)
throw InputError(
"pfqn_ncldmx: D and N disagree on the class count");
188 if (lambda.size() != R)
189 throw InputError(
"pfqn_ncldmx: lambda and D disagree on the class count");
190 if (mu.
rows() != M)
throw InputError(
"pfqn_ncldmx: mu and D disagree on the station count");
195 std::vector<std::size_t> openCl, closedCl;
196 for (std::size_t r = 0; r < R; ++r) (N[r] < 0 ? openCl : closedCl).push_back(r);
197 for (std::size_t r : closedCl)
198 if (lambda[r] != zero)
199 throw InputError(
"pfqn_ncldmx: an arrival rate is specified on a closed class");
201 std::vector<int> Nc(closedCl.size(), 0);
203 for (std::size_t a = 0; a < closedCl.size(); ++a) {
204 Nc[a] = N[closedCl[a]];
207 const std::size_t width =
static_cast<std::size_t
>(Kc > 0 ? Kc : 1);
220 const std::size_t padCols = (mu.
cols() > width ? mu.
cols() : width) + 1;
222 for (std::size_t i = 0; i < M; ++i)
223 for (std::size_t k = 0; k < padCols; ++k)
224 mup(i, k) = mu.
cols() == 0 ? one : mu(i, k < mu.
cols() ? k : mu.
cols() - 1);
226 std::vector<T> lambdao(R, zero);
227 for (std::size_t r : openCl) lambdao[r] = lambda[r];
241 bool openDiverges =
false;
242 for (std::size_t i = 0; i < M; ++i)
243 if (ec.
E(i, 0) <= zero) { openDiverges =
true;
break; }
245 res.
lGopen = std::numeric_limits<double>::infinity();
252 for (std::size_t i = 0; i < M; ++i) res.
Gopen *= ec.
E(i, 0);
256 for (std::size_t i = 0; i < M; ++i) res.
Gopen *= ec.
E(i, 0);
261 for (std::size_t i = 0; i < M; ++i)
262 for (std::size_t a = 0; a < closedCl.size(); ++a) Dc(i, a) = D(i, closedCl[a]);
264 for (std::size_t i = 0; i < Zc.
rows(); ++i)
265 for (std::size_t a = 0; a < closedCl.size(); ++a) Zc(i, a) = Z(i, closedCl[a]);
268 for (std::size_t i = 0; i < M; ++i)
269 for (std::size_t k = 0; k < width; ++k) {
270 if (ec.
EC(i, k) == zero)
271 throw NumericError(
"pfqn_ncldmx: an effective capacity term is zero");
272 muEff(i, k) = one / ec.
EC(i, k);
285 const std::size_t C = closedCl.size();
286 res.
XN.assign(R, zero);
288 for (std::size_t r : openCl) res.
XN[r] = lambda[r];
290 std::vector<double> lGr(C > 0 ? C : 1, 0.0);
292 for (std::size_t a = 0; a < C; ++a) {
293 if (Nc[a] <= 0)
continue;
294 std::vector<int> Ncr = Nc;
296 lGr[a] = detail::ncldmx_lg(Dc, Ncr, Zc, muEff, method, atol, nopt);
301 for (std::size_t i = 0; i < M; ++i) {
302 bool anyDemand =
false;
303 for (std::size_t a = 0; a < C; ++a)
304 if (Dc(i, a) > zero) { anyDemand =
true;
break; }
305 if (!anyDemand)
continue;
308 for (std::size_t k = 0; k < muhat.
cols(); ++k) muhatRow(0, k) = muhat(i, k);
311 const Matrix<T> Dminus = detail::ncldmx_drop_row(Dc, i);
312 const Matrix<T> muminus = detail::ncldmx_drop_row(muEff, i);
314 for (std::size_t i2 = 0; i2 < M; ++i2)
315 for (std::size_t a = 0; a < C; ++a) DcPlus(i2, a) = Dc(i2, a);
316 for (std::size_t a = 0; a < C; ++a) DcPlus(M, a) = Dc(i, a);
318 for (std::size_t i2 = 0; i2 < M; ++i2)
319 for (std::size_t k = 0; k < muhat.
cols(); ++k) muhatPlus(i2, k) = muhat(i2, k);
320 for (std::size_t k = 0; k < muhat.
cols() && k < fnc.
mu.cols(); ++k)
321 muhatPlus(M, k) = fnc.
mu(0, k);
322 for (std::size_t a = 0; a < C; ++a) {
323 if (Nc[a] <= 0 || !(Dc(i, a) > zero))
continue;
324 std::vector<int> Ncr = Nc;
326 const double lGhat = detail::ncldmx_lg(Dc, Ncr, Zc, muhat, method, atol, nopt);
327 const double lGhatf =
328 detail::ncldmx_lg(DcPlus, Ncr, Zc, muhatPlus, method, atol, nopt);
329 const double lGminus =
330 detail::ncldmx_lg(Dminus, Ncr, Zc, muminus, method, atol, nopt);
332 (std::exp(lGhatf - lGhat) - 1.0) + cshift * (std::exp(lGminus - lGhat) - 1.0);
342 if (!openCl.empty()) {
343 for (std::size_t i = 0; i < M; ++i) {
345 for (std::size_t a = 0; a < C; ++a)
347 const std::size_t b = detail::ncldmx_lld_level(mup, i);
348 const std::size_t bcap = b < ec.
EC.cols() ? b : ec.
EC.cols();
350 double acc = ECinf * (Qtot + 1.0);
352 const Matrix<T> Dminus = detail::ncldmx_drop_row(Dc, i);
353 const Matrix<T> muminus = detail::ncldmx_drop_row(muEff, i);
355 for (std::size_t a = 0; a < C; ++a) Drow(0, a) = Dc(i, a);
356 for (std::size_t k = 0; k < muEff.
cols(); ++k) murow(0, k) = muEff(i, k);
358 for (std::size_t n = 0; n + 2 <= b; ++n) {
360 if (delta == 0.0)
continue;
370 Pn = n == 0 ? 1.0 : 0.0;
372 std::vector<std::vector<int> > ks;
373 std::vector<int> cur(C, 0);
375 detail::ncldmx_compositions(
static_cast<int>(n), Nc, 0, cur, ks);
377 ks.push_back(std::vector<int>());
378 for (std::size_t t = 0; t < ks.size(); ++t) {
379 std::vector<int> rest(C, 0);
380 for (std::size_t a = 0; a < C; ++a) rest[a] = Nc[a] - ks[t][a];
381 const double lF = n == 0 ? 0.0
382 : detail::ncldmx_lg(Drow, ks[t], Zzero, murow,
385 detail::ncldmx_lg(Dminus, rest, Zc, muminus, method, atol, nopt);
386 Pn += std::exp(lF + lGbar - res.
lG);
389 acc +=
static_cast<double>(n + 1) * delta * Pn;
392 for (std::size_t r : openCl)