152 const std::vector<SchedStrategy>& sched) {
154 "pfqn_schmidt_ext requires transcendental arithmetic: its alpha correction is "
155 "an approximation drawn from an auxiliary approximate solve, and its marginal "
156 "probabilities use non-integer binomial powers");
158 const std::size_t M = D.
rows();
159 const std::size_t R = N.size();
161 throw InputError(
"pfqn_schmidt_ext: D and N disagree on the class count");
162 if (sched.size() != M)
throw InputError(
"pfqn_schmidt_ext: sched has the wrong station count");
164 throw InputError(
"pfqn_schmidt_ext: server-count matrix has the wrong shape");
166 if (n < 0)
throw InputError(
"pfqn_schmidt_ext: negative population");
174 res.
XN.assign(R, zero);
178 if (M == 0 || R == 0)
return res;
180 const auto nserv = [&](std::size_t i, std::size_t c) {
181 return S.
cols() == 1 ? S(i, 0) : S(i, c);
183 std::vector<bool> classIndep(M,
true);
184 for (std::size_t i = 0; i < M; ++i)
185 for (std::size_t c = 1; c < R; ++c)
186 if (D(i, c) != D(i, 0)) classIndep[i] =
false;
189 std::vector<Matrix<T>> alphas(M * R);
190 for (std::size_t i = 0; i < M; ++i) {
194 "pfqn_schmidt_ext: a class-dependent FCFS station needs the alpha correction, "
195 "whose auxiliary solve widens the model to R+1 classes; pass a per-station "
196 "(M x 1) server vector");
197 for (std::size_t r = 0; r < R; ++r) {
199 std::vector<int> Nmod(R + 1, 0);
200 for (std::size_t k = 0; k < R; ++k) {
201 Nmod[k] = k == r ? N[k] - 1 : N[k];
202 for (std::size_t j = 0; j < M; ++j) {
203 Dmod(j, k) = D(j, k);
204 Dmod(j, R) = j == i ? D(j, r) : zero;
210 "pfqn_schmidt_ext: a class-dependent FCFS station needs the alpha correction "
211 "at N - e_r, which is negative for an empty class");
212 alphas[i * R + r] =
pfqn_schmidt(Dmod, Nmod, S, sched).UN;
217 const std::vector<std::size_t> prods =
plane_sizes(N);
220 for (
int n : N) Ntot += n;
222 std::vector<detail::SchmidtPc> kind(M, detail::SchmidtPc::None);
223 for (std::size_t i = 0; i < M; ++i) {
225 for (std::size_t c = 0; c < (S.
cols() == 1 ? std::size_t(1) : R); ++c)
226 if (nserv(i, c) != 1) single =
false;
231 if (!single) kind[i] = detail::SchmidtPc::Scalar;
235 if (!single) kind[i] = detail::SchmidtPc::Scalar;
237 kind[i] = detail::SchmidtPc::Vector;
243 std::vector<Matrix<T>> Lq(M,
Matrix<T>(R, total, zero));
244 std::vector<Matrix<T>> Pc(M);
245 for (std::size_t i = 0; i < M; ++i) {
246 if (kind[i] == detail::SchmidtPc::Scalar)
247 Pc[i] =
Matrix<T>(
static_cast<std::size_t
>(1 + Ntot), total, zero);
248 else if (kind[i] == detail::SchmidtPc::Vector)
250 if (kind[i] != detail::SchmidtPc::None) Pc[i](0, 0) = one;
254 std::vector<T> w(M * R * total, zero);
256 std::vector<int> kvec(R, 0);
257 std::size_t hlast = 0;
260 const std::size_t hk =
pop_index(kvec, prods);
263 for (
int t : kvec) kpop += t;
265 for (std::size_t i = 0; i < M; ++i)
266 for (std::size_t c = 0; c < R; ++c) {
267 if (kvec[c] <= 0)
continue;
268 const std::size_t hkc = hk - prods[c];
269 const int ns = nserv(i, c);
270 T& wi = w[(i * R + c) * total + hk];
275 const bool vectorPc = kind[i] == detail::SchmidtPc::Vector;
276 if (!vectorPc || ns == 1) {
278 for (std::size_t r = 0; r < R; ++r) qtot += Lq[i](r, hkc);
280 wi = D(i, c) * (one + qtot);
283 wi = D(i, c) / nsT * (one + qtot);
284 for (
int j = 1; j <= ns - 1; ++j)
286 Pc[i](
static_cast<std::size_t
>(j - 1), hkc) * (D(i, c) / nsT);
289 std::vector<int> nvec(R, 0);
293 const std::size_t hnc =
pop_index(nvec, prods) - prods[c];
295 const T Bcn = (N[c] > 1 && !al.
empty())
296 ? detail::schmidt_ext_bcn_ext(al, D, i, c, nvec, R, ns)
297 : detail::schmidt_ext_bcn(D, i, c, nvec, ns);
298 wi += Bcn * Pc[i](hnc, hkc);
305 for (std::size_t c = 0; c < R; ++c) {
307 for (std::size_t i = 0; i < M; ++i) denom += w[(i * R + c) * total + hk];
311 for (std::size_t i = 0; i < M; ++i) {
312 for (std::size_t c = 0; c < R; ++c)
313 Lq[i](c, hk) = xtab(c, hk) * w[(i * R + c) * total + hk];
317 const int nsLast = nserv(i, R - 1);
318 const int s0 = nserv(i, 0);
321 if (nsLast > 1 && kind[i] == detail::SchmidtPc::Scalar) {
322 const long top = s0 < kpop ? s0 : kpop;
323 for (
long n = 1; n <= top; ++n)
324 for (std::size_t c = 0; c < R; ++c) {
325 if (kvec[c] <= 0)
continue;
326 const std::size_t hkc = hk - prods[c];
327 Pc[i](
static_cast<std::size_t
>(n), hk) +=
329 Pc[i](
static_cast<std::size_t
>(n - 1), hkc);
333 for (
long n = 1; n <= top; ++n)
334 acc += Pc[i](
static_cast<std::size_t
>(n), hk);
335 const T p0 = one - acc;
336 Pc[i](0, hk) = p0 > epsT ? p0 : epsT;
340 if (kind[i] == detail::SchmidtPc::Vector) {
342 std::vector<int> nvec(R, 0);
345 const std::size_t hn =
pop_index(nvec, prods);
347 for (
int t : nvec) nsum += t;
349 for (std::size_t r = 0; r < R; ++r) {
350 if (nvec[r] <= 0)
continue;
351 const std::size_t hnc = hn - prods[r];
352 const std::size_t hkc = hk - prods[r];
353 const int nsr = nserv(i, r);
356 (N[r] > 1 && !al.
empty())
357 ? detail::schmidt_ext_bcn_ext(al, D, i, r, nvec, R, nsr)
358 : detail::schmidt_ext_bcn(D, i, r, nvec, nsr);
362 Pc[i](hn, hk) = prob;
366 const T p0 = one - sumAll;
367 Pc[i](0, hk) = p0 > tiny ? p0 : tiny;
368 }
else if (nsLast > 1 && kind[i] == detail::SchmidtPc::Scalar) {
371 for (std::size_t r = 0; r < R; ++r)
372 if (D(i, r) > zero) Kj += N[r];
374 for (std::size_t r = 0; r < R; ++r) meanQ += Lq[i](r, hk);
375 const long top = (nsLast < kpop ? nsLast : kpop) - 1;
376 for (
long n = 1; n <= top; ++n) {
377 if (Kj <= 0 || n > Kj)
continue;
379 Pc[i](
static_cast<std::size_t
>(n), hk) =
380 num_nck<T>(
static_cast<int>(Kj),
static_cast<int>(n)) *
382 num_pow_int(T(one - frac),
static_cast<unsigned>(Kj - n));
384 T sum1 = zero, sum2 = zero;
385 for (std::size_t r = 0; r < R; ++r) sum1 += D(i, r) * xtab(r, hk);
386 for (
long n = 0; n <= nsLast - 1; ++n)
388 Pc[i](
static_cast<std::size_t
>(n), hk);
390 Pc[i](0, hk) = p0 > tiny ? p0 : tiny;
398 for (std::size_t c = 0; c < R; ++c) res.
XN[c] = xtab(c, hlast);
399 for (std::size_t i = 0; i < M; ++i)
400 for (std::size_t c = 0; c < R; ++c) {
402 res.
CN(i, c) = w[(i * R + c) * total + hlast];
403 res.
QN(i, c) = Lq[i](c, hlast);