156 const std::size_t R0 = N.size();
167 if (v < 0)
throw InputError(
"pfqn_ncld: negative population");
170 if (Ntot == 0)
return res;
171 const std::size_t M0 = L.
empty() ? 0 : L.
rows();
172 if (M0 > 0 && L.
cols() != R0)
173 throw InputError(
"pfqn_ncld: L and N disagree on the class count");
174 if (M0 > 0 && mu.
rows() != M0)
175 throw InputError(
"pfqn_ncld: mu and L disagree on the station count");
176 if (M0 > 0 &&
static_cast<long>(mu.
cols()) < Ntot)
177 throw InputError(
"pfqn_ncld: mu has fewer rate columns than the total population");
178 const std::size_t Nt =
static_cast<std::size_t
>(Ntot);
181 std::vector<std::size_t> nnz;
182 for (std::size_t r = 0; r < R0; ++r)
183 if (N[r] > 0) nnz.push_back(r);
184 const std::size_t R1 = nnz.size();
187 std::vector<T> scalevec(R1, one);
189 for (std::size_t k = 0; k < R1; ++k) {
190 const std::size_t r = nnz[k];
192 for (std::size_t i = 0; i < M0; ++i)
193 if (L(i, r) > mx) mx = L(i, r);
194 for (std::size_t i = 0; i < Z1.
rows(); ++i)
195 if (Z(i, r) > mx) mx = Z(i, r);
196 if (mx > zero) scalevec[k] = mx;
197 for (std::size_t i = 0; i < M0; ++i) L1(i, k) = L(i, r) / scalevec[k];
198 for (std::size_t i = 0; i < Z1.
rows(); ++i) Z1(i, k) = Z(i, r) / scalevec[k];
201 for (std::size_t k = 0; k < R1; ++k)
202 Gscale *=
num_pow_int(scalevec[k],
static_cast<unsigned>(N[nnz[k]]));
205 std::vector<std::size_t> demSt;
206 for (std::size_t i = 0; i < M0; ++i) {
208 for (std::size_t k = 0; k < R1; ++k) rs += L1(i, k);
209 if (rs > atol) demSt.push_back(i);
211 const std::size_t M = demSt.size();
213 for (std::size_t a = 0; a < M; ++a) {
214 for (std::size_t k = 0; k < R1; ++k) L2(a, k) = L1(demSt[a], k);
215 for (std::size_t k = 0; k < Nt; ++k) mu2(a, k) = mu(demSt[a], k);
218 std::vector<int> N2(R1, 0);
219 for (std::size_t k = 0; k < R1; ++k) N2[k] = N[nnz[k]];
221 const auto delayG = [&](
const std::vector<std::size_t>& cls) {
223 for (std::size_t k : cls) {
225 for (std::size_t i = 0; i < Z1.
rows(); ++i) zs += Z1(i, k);
226 g *=
num_pow_int(zs,
static_cast<unsigned>(N2[k])) /
231 const auto finish = [&](
const T& gcore) {
232 res.
G = Gscale * gcore;
239 const auto finish_log = [&](
double lgcore) {
246 for (std::size_t i = 0; i < Z1.
rows(); ++i)
247 for (std::size_t k = 0; k < R1; ++k) Ztot += Z1(i, k);
249 for (std::size_t a = 0; a < M; ++a)
250 for (std::size_t k = 0; k < R1; ++k) Lsum += L2(a, k);
252 if (M == 0 || !(Lsum > atol)) {
253 std::vector<std::size_t> all(R1);
254 for (std::size_t k = 0; k < R1; ++k) all[k] = k;
255 return finish(Ztot > atol ? delayG(all) : one);
257 if (M == 1 && !(Ztot > atol)) {
261 for (
int v : N2) tot += v;
263 for (std::size_t k = 0; k < R1; ++k)
264 g *=
num_pow_int(L2(0, k),
static_cast<unsigned>(N2[k])) /
266 for (std::size_t k = 0; k < Nt; ++k) {
267 if (mu2(0, k) == zero)
throw NumericError(
"pfqn_ncld: a load-dependent rate is zero");
274 std::vector<std::size_t> zdem, nzdem;
275 for (std::size_t k = 0; k < R1; ++k) {
277 for (std::size_t a = 0; a < M; ++a) s += L2(a, k);
278 (s > atol ? nzdem : zdem).push_back(k);
280 const T Gzdem = zdem.empty() ? one : delayG(zdem);
282 const std::size_t Rc = nzdem.size();
284 std::vector<int> N3(Rc, 0);
285 for (std::size_t a = 0; a < Rc; ++a) {
286 for (std::size_t i = 0; i < M; ++i) L3(i, a) = L2(i, nzdem[a]);
287 for (std::size_t i = 0; i < Z1.
rows(); ++i) Z3(i, a) = Z1(i, nzdem[a]);
288 N3[a] = N2[nzdem[a]];
291 for (std::size_t i = 0; i < Z3.
rows(); ++i)
292 for (std::size_t a = 0; a < Rc; ++a) Z3tot += Z3(i, a);
300 for (
int v : N3) Nsum3 += v;
301 bool default_clw =
false;
311 std::vector<int> lat;
312 std::vector<double> gam;
319 std::vector<std::size_t> keep(Rc), depth(Rc);
320 for (std::size_t a = 0; a < Rc; ++a) {
324 detail::clw_defaults(Rc, keep, depth,
ClwOptions(), lat, gam);
326 for (std::size_t a = 0; a < Rc; ++a)
327 cost *= 2.0 *
static_cast<double>(lat[a]) *
static_cast<double>(N3[a]);
328 default_clw = cost <= 2e7;
334 const bool comomld_falls_back =
336 const bool logdomain = default_clw || comomld_falls_back || method ==
NcldMethod::Is ||
350 ? std::string(
"comomld (which falls back to 'rd' on a multi-station model "
351 "with a delay, CoMoM-LD carrying only the delay-plus-identical-"
357 std::vector<T> Zv(Rc, zero);
358 for (std::size_t i = 0; i < Z3.
rows(); ++i)
359 for (std::size_t a = 0; a < Rc; ++a) Zv[a] += Z3(i, a);
378 std::string(
"pfqn_ncld: the 'panald' asymptotic expansion does not "
379 "apply to this model: ") +
381 ". Use 'exact', 'clw' or an approximate load-dependent method instead");
386 std::vector<T> Nv(Rc, zero);
387 for (std::size_t a = 0; a < Rc; ++a) Nv[a] = num_traits<T>::from_int(N3[a]);
392 std::vector<T> Nv(Rc, zero);
393 for (std::size_t a = 0; a < Rc; ++a) Nv[a] = num_traits<T>::from_int(N3[a]);
398 std::vector<T> Nv(Rc, zero);
399 for (std::size_t a = 0; a < Rc; ++a) Nv[a] = num_traits<T>::from_int(N3[a]);
412 "pfqn_ncld: the 'divdiff' method requires a model without think time, "
413 "which needs the integral form of Corollary 3.4. Use 'exact' or "
423 "pfqn_ncld: the 'divdiff' closed form was exhausted by cancellation on "
424 "this model (" + std::to_string(ex.
lossDigits) +
425 " decimal digits lost). Use 'exact', 'comomld' or 'rd', or merge the "
426 "near-tied scaled demands with a looser tolerance");
432 return finish_log(lgz +
pfqn_rd(L3, N3, Z3, mu2).lGN);
445 const std::size_t D = Z3tot > atol ? Z3.
rows() : 0;
447 for (std::size_t i = 0; i < M; ++i) {
448 for (std::size_t a = 0; a < Rc; ++a) Lz(i, a) = L3(i, a);
449 for (std::size_t k = 0; k < Nt; ++k) muz(i, k) = mu2(i, k);
451 for (std::size_t d = 0; d < D; ++d) {
452 for (std::size_t a = 0; a < Rc; ++a) Lz(M + d, a) = Z3(d, a);
453 for (std::size_t k = 0; k < Nt; ++k)
462 }
else if (M == 1 && Z3tot > atol) {
464 res.
method =
"exact/comomld";
467 res.
method =
"exact/comomld";
473 return finish(Gzdem * gcore);