168 const Matrix<T>& mu,
const std::string& method_name,
const T& atol,
170 const std::size_t R0 = N.size();
187 if (v < 0)
throw InputError(
"pfqn_ncld: negative population");
190 if (Ntot == 0)
return res;
191 const std::size_t M0 = L.
empty() ? 0 : L.
rows();
192 if (M0 > 0 && L.
cols() != R0)
193 throw InputError(
"pfqn_ncld: L and N disagree on the class count");
194 if (M0 > 0 && mu.
rows() != M0)
195 throw InputError(
"pfqn_ncld: mu and L disagree on the station count");
196 if (M0 > 0 &&
static_cast<long>(mu.
cols()) < Ntot)
197 throw InputError(
"pfqn_ncld: mu has fewer rate columns than the total population");
198 const std::size_t Nt =
static_cast<std::size_t
>(Ntot);
201 std::vector<std::size_t> nnz;
202 for (std::size_t r = 0; r < R0; ++r)
203 if (N[r] > 0) nnz.push_back(r);
204 const std::size_t R1 = nnz.size();
207 std::vector<T> scalevec(R1, one);
209 for (std::size_t k = 0; k < R1; ++k) {
210 const std::size_t r = nnz[k];
212 for (std::size_t i = 0; i < M0; ++i)
213 if (L(i, r) > mx) mx = L(i, r);
214 for (std::size_t i = 0; i < Z1.
rows(); ++i)
215 if (Z(i, r) > mx) mx = Z(i, r);
216 if (mx > zero) scalevec[k] = mx;
217 for (std::size_t i = 0; i < M0; ++i) L1(i, k) = L(i, r) / scalevec[k];
218 for (std::size_t i = 0; i < Z1.
rows(); ++i) Z1(i, k) = Z(i, r) / scalevec[k];
221 for (std::size_t k = 0; k < R1; ++k)
222 Gscale *=
num_pow_int(scalevec[k],
static_cast<unsigned>(N[nnz[k]]));
225 std::vector<std::size_t> demSt;
226 for (std::size_t i = 0; i < M0; ++i) {
228 for (std::size_t k = 0; k < R1; ++k) rs += L1(i, k);
229 if (rs > atol) demSt.push_back(i);
231 const std::size_t M = demSt.size();
233 for (std::size_t a = 0; a < M; ++a) {
234 for (std::size_t k = 0; k < R1; ++k) L2(a, k) = L1(demSt[a], k);
235 for (std::size_t k = 0; k < Nt; ++k) mu2(a, k) = mu(demSt[a], k);
238 std::vector<int> N2(R1, 0);
239 for (std::size_t k = 0; k < R1; ++k) N2[k] = N[nnz[k]];
241 const auto delayG = [&](
const std::vector<std::size_t>& cls) {
243 for (std::size_t k : cls) {
245 for (std::size_t i = 0; i < Z1.
rows(); ++i) zs += Z1(i, k);
246 g *=
num_pow_int(zs,
static_cast<unsigned>(N2[k])) /
251 const auto finish = [&](
const T& gcore) {
252 res.
G = Gscale * gcore;
259 const auto finish_log = [&](
double lgcore) {
266 for (std::size_t i = 0; i < Z1.
rows(); ++i)
267 for (std::size_t k = 0; k < R1; ++k) Ztot += Z1(i, k);
269 for (std::size_t a = 0; a < M; ++a)
270 for (std::size_t k = 0; k < R1; ++k) Lsum += L2(a, k);
272 if (M == 0 || !(Lsum > atol)) {
273 std::vector<std::size_t> all(R1);
274 for (std::size_t k = 0; k < R1; ++k) all[k] = k;
275 return finish(Ztot > atol ? delayG(all) : one);
277 if (M == 1 && !(Ztot > atol)) {
281 for (
int v : N2) tot += v;
283 for (std::size_t k = 0; k < R1; ++k)
284 g *=
num_pow_int(L2(0, k),
static_cast<unsigned>(N2[k])) /
286 for (std::size_t k = 0; k < Nt; ++k) {
287 if (mu2(0, k) == zero)
throw NumericError(
ErrorKind{
"Degenerate"},
"pfqn_ncld: a load-dependent rate is zero");
294 std::vector<std::size_t> zdem, nzdem;
295 for (std::size_t k = 0; k < R1; ++k) {
297 for (std::size_t a = 0; a < M; ++a) s += L2(a, k);
298 (s > atol ? nzdem : zdem).push_back(k);
300 const T Gzdem = zdem.empty() ? one : delayG(zdem);
302 const std::size_t Rc = nzdem.size();
304 std::vector<int> N3(Rc, 0);
305 for (std::size_t a = 0; a < Rc; ++a) {
306 for (std::size_t i = 0; i < M; ++i) L3(i, a) = L2(i, nzdem[a]);
307 for (std::size_t i = 0; i < Z1.
rows(); ++i) Z3(i, a) = Z1(i, nzdem[a]);
308 N3[a] = N2[nzdem[a]];
311 for (std::size_t i = 0; i < Z3.
rows(); ++i)
312 for (std::size_t a = 0; a < Rc; ++a) Z3tot += Z3(i, a);
324 for (
int v : N3) Nsum3 += v;
325 bool default_clw =
false;
335 std::vector<int> lat;
336 std::vector<double> gam;
341 std::vector<std::size_t> keep(Rc), depth(Rc);
342 for (std::size_t a = 0; a < Rc; ++a) {
346 detail::clw_defaults(Rc, keep, depth,
ClwOptions(), lat, gam);
348 for (std::size_t a = 0; a < Rc; ++a)
349 cost *= 2.0 *
static_cast<double>(lat[a]) *
static_cast<double>(N3[a]);
350 default_clw = cost <= 2e7;
356 const bool comomld_falls_back =
358 const bool logdomain = default_clw || comomld_falls_back || method ==
NcldMethod::Is ||
372 ? std::string(
"comomld (which falls back to 'rd' on a multi-station model "
373 "with a delay, CoMoM-LD carrying only the delay-plus-identical-"
379 std::vector<T> Zv(Rc, zero);
380 for (std::size_t i = 0; i < Z3.
rows(); ++i)
381 for (std::size_t a = 0; a < Rc; ++a) Zv[a] += Z3(i, a);
400 std::string(
"pfqn_ncld: the 'panald' asymptotic expansion does not "
401 "apply to this model: ") +
403 ". Use 'exact', 'clw' or an approximate load-dependent method instead");
408 std::vector<T> Nv(Rc, zero);
409 for (std::size_t a = 0; a < Rc; ++a) Nv[a] = num_traits<T>::from_int(N3[a]);
414 std::vector<T> Nv(Rc, zero);
415 for (std::size_t a = 0; a < Rc; ++a) Nv[a] = num_traits<T>::from_int(N3[a]);
420 std::vector<T> Nv(Rc, zero);
421 for (std::size_t a = 0; a < Rc; ++a) Nv[a] = num_traits<T>::from_int(N3[a]);
434 "pfqn_ncld: the 'divdiff' method requires a model without think time, "
435 "which needs the integral form of Corollary 3.4. Use 'exact' or "
443 if (!ex.valid || ex.lossDigits > 15)
445 "pfqn_ncld: the 'divdiff' closed form was exhausted by cancellation on "
446 "this model (" + std::to_string(ex.lossDigits) +
447 " decimal digits lost). Use 'exact', 'comomld' or 'rd', or merge the "
448 "near-tied scaled demands with a looser tolerance");
449 res.
method =
"divdiff.ld/" + ex.method;
454 return finish_log(lgz +
pfqn_rd(L3, N3, Z3, mu2).lGN);
467 const std::size_t D = Z3tot > atol ? Z3.
rows() : 0;
469 for (std::size_t i = 0; i < M; ++i) {
470 for (std::size_t a = 0; a < Rc; ++a) Lz(i, a) = L3(i, a);
471 for (std::size_t k = 0; k < Nt; ++k) muz(i, k) = mu2(i, k);
473 for (std::size_t d = 0; d < D; ++d) {
474 for (std::size_t a = 0; a < Rc; ++a) Lz(M + d, a) = Z3(d, a);
475 for (std::size_t k = 0; k < Nt; ++k)
484 }
else if (M == 1 && Z3tot > atol) {
486 res.
method =
"exact/comomld";
489 res.
method =
"exact/comomld";
495 return finish(Gzdem * gcore);