218 const Matrix<T>& L,
const std::vector<int>& N,
const std::vector<T>& Z,
219 const std::vector<std::pair<std::size_t, std::size_t>>& pairs,
QlenJointRoute route,
222 "pfqn_qlen_joint_moments assembles the survival array in the log domain and "
223 "needs transcendental arithmetic");
226 const std::size_t M = L.
rows();
227 const std::size_t R = L.
cols();
231 "pfqn_qlen_joint_moments: the population vector N must have one entry per class");
232 std::vector<T> Zv = Z;
233 if (Zv.empty()) Zv.assign(R, zero);
236 "pfqn_qlen_joint_moments: the think time vector Z must have one entry per class");
238 for (std::size_t r = 0; r < R; ++r) Zm(0, r) = Zv[r];
240 std::vector<std::pair<std::size_t, std::size_t>> pr = pairs;
242 for (std::size_t i = 0; i < M; ++i)
243 for (std::size_t r = 0; r < R; ++r) pr.push_back(std::make_pair(i, r));
245 for (std::size_t j = 0; j < pr.size(); ++j)
246 if (pr[j].first >= M || pr[j].second >= R)
247 throw InputError(
"pfqn_qlen_joint_moments: a (station,class) pair is out of range");
249 std::vector<std::pair<std::size_t, std::size_t>> s = pr;
250 std::sort(s.begin(), s.end());
251 if (std::unique(s.begin(), s.end()) != s.end())
252 throw InputError(
"pfqn_qlen_joint_moments: the (station,class) pairs must be distinct");
258 "pfqn_qlen_joint_moments: the tail route needs the geometric occupancy of a "
259 "single-class load-independent station; with several classes the multinomial factor "
260 "breaks the survival identity, so use the pmf route");
262 const std::size_t d = pr.size();
263 std::vector<std::size_t> dims(d);
264 for (std::size_t j = 0; j < d; ++j)
265 dims[j] =
static_cast<std::size_t
>(N[pr[j].second]) + 1;
273 std::size_t served = 0, evals = 0, points = 0;
277 std::vector<std::vector<int>> need;
278 std::vector<std::size_t> a(d, 0);
281 for (std::size_t j = 0; j < d; ++j) s += static_cast<long>(a[j]);
282 if (
static_cast<long>(N[0]) - s >= 0) {
283 std::vector<int> row(1,
static_cast<int>(
static_cast<long>(N[0]) - s));
284 if (std::find(need.begin(), need.end(), row) == need.end()) need.push_back(row);
286 }
while (detail::qlen_odometer(a, dims));
287 if (std::find(need.begin(), need.end(), N) == need.end()) need.push_back(N);
288 std::sort(need.begin(), need.end());
290 std::size_t sv = 0, ev = 0;
291 const std::vector<double> lg =
292 detail::qlen_batch_lg(L, need, Zm, lGsrc, method, nopt, sv, ev);
295 points = need.size();
296 const double lgN = lg[detail::qlen_findrow(need, N)];
298 std::fill(a.begin(), a.end(),
static_cast<std::size_t
>(0));
302 for (std::size_t j = 0; j < d; ++j) s += static_cast<long>(a[j]);
303 if (static_cast<long>(N[0]) - s >= 0) {
306 for (std::size_t j = 0; j < d; ++j) {
307 if (a[j] == 0) continue;
308 const T Lij = L(pr[j].first, pr[j].second);
313 acc += static_cast<double>(a[j]) * num_traits<T>::log_as_double(Lij);
316 std::vector<int> key(1, static_cast<int>(static_cast<long>(N[0]) - s));
317 tail.data[ia] = num_traits<T>::from_double(
318 std::exp(acc + lg[detail::qlen_findrow(need, key)] - lgN));
322 }
while (detail::qlen_odometer(a, dims));
327 std::vector<std::size_t> stations;
328 for (std::size_t j = 0; j < d; ++j) stations.push_back(pr[j].first);
329 std::sort(stations.begin(), stations.end());
330 stations.erase(std::unique(stations.begin(), stations.end()), stations.end());
331 std::vector<std::pair<std::size_t, std::size_t>> coords;
332 for (std::size_t si = 0; si < stations.size(); ++si)
333 for (std::size_t r = 0; r < R; ++r) coords.push_back(std::make_pair(stations[si], r));
334 const std::size_t dc = coords.size();
335 std::vector<std::size_t> cdims(dc);
336 for (std::size_t j = 0; j < dc; ++j)
337 cdims[j] =
static_cast<std::size_t
>(N[coords[j].second]) + 1;
339 std::vector<std::size_t> keep;
340 for (std::size_t i = 0; i < M; ++i)
341 if (std::find(stations.begin(), stations.end(), i) == stations.end()) keep.push_back(i);
343 for (std::size_t k = 0; k < keep.size(); ++k)
344 for (std::size_t r = 0; r < R; ++r) Lsub(k, r) = L(keep[k], r);
346 std::vector<std::vector<int>> need;
347 std::vector<std::size_t> a(dc, 0);
349 std::vector<int> n = N;
350 for (std::size_t j = 0; j < dc; ++j) n[coords[j].second] -=
static_cast<int>(a[j]);
352 for (std::size_t r = 0; r < R; ++r)
353 if (n[r] < 0) ok =
false;
354 if (ok && std::find(need.begin(), need.end(), n) == need.end()) need.push_back(n);
355 }
while (detail::qlen_odometer(a, cdims));
356 std::sort(need.begin(), need.end());
358 std::vector<double> lgc(need.size(), 0.0);
360 for (std::size_t p = 0; p < need.size(); ++p) lgc[p] = detail::qlen_delay_lg(Zv, need[p]);
361 served = need.size();
364 std::size_t sv = 0, ev = 0;
365 lgc = detail::qlen_batch_lg(Lsub, need, Zm, lGsrc, method, nopt, sv, ev);
369 points = need.size();
371 std::size_t sv0 = 0, ev0 = 0;
373 const std::vector<std::vector<int>> onlyN(1, N);
374 const std::vector<double> lgNv =
375 detail::qlen_batch_lg(L, onlyN, Zm, none, method, nopt, sv0, ev0);
376 const double lgN = lgNv[0];
379 moment::MomentTensor<T> marg(dims);
380 std::fill(a.begin(), a.end(),
static_cast<std::size_t
>(0));
382 std::vector<int> n = N;
383 for (std::size_t j = 0; j < dc; ++j) n[coords[j].second] -=
static_cast<int>(a[j]);
385 for (std::size_t r = 0; r < R; ++r)
386 if (n[r] < 0) inbox =
false;
387 if (!inbox)
continue;
388 const double gc = lgc[detail::qlen_findrow(need, n)];
389 if (!std::isfinite(gc))
continue;
390 double acc = gc - lgN;
392 for (std::size_t si = 0; si < stations.size() && ok; ++si) {
393 const std::size_t i = stations[si];
395 for (std::size_t j = 0; j < dc; ++j)
396 if (coords[j].first == i) tot +=
static_cast<long>(a[j]);
397 acc += num_traits<T>::to_double(
398 detail::num_lgamma<T>(num_traits<T>::from_int(tot + 1)));
399 for (std::size_t j = 0; j < dc; ++j) {
400 if (coords[j].first != i || a[j] == 0)
continue;
401 const T Lir = L(i, coords[j].second);
406 acc +=
static_cast<double>(a[j]) * num_traits<T>::log_as_double(Lir) -
407 num_traits<T>::to_double(detail::num_lgamma<T>(
408 num_traits<T>::from_int(
static_cast<long>(a[j]) + 1)));
412 std::vector<std::size_t> sub(d, 0);
413 for (std::size_t j = 0; j < d; ++j)
414 for (std::size_t jc = 0; jc < dc; ++jc)
415 if (coords[jc] == pr[j]) sub[j] = a[jc];
416 marg.at(detail::qlen_trunc(marg, sub)) += num_traits<T>::from_double(std::exp(acc));
417 }
while (detail::qlen_odometer(a, cdims));
421 for (std::size_t mode = 0; mode < tail.order(); ++mode) {
422 const std::size_t n = tail.sz[mode];
423 std::size_t stride = 1;
424 for (std::size_t l = 0; l < mode; ++l) stride *= tail.sz[l];
425 const std::size_t outer = tail.numel() / (n * stride);
426 for (std::size_t o = 0; o < outer; ++o)
427 for (std::size_t s = 0; s < stride; ++s) {
428 const std::size_t base = o * n * stride + s;
429 for (std::size_t k = n - 1; k-- > 0;)
430 tail.data[base + k * stride] += tail.data[base + (k + 1) * stride];
442 res.mean.assign(d, zero);
444 for (std::size_t j = 0; j < d; ++j) {
445 std::vector<std::size_t> e(d, 0);
447 res.mean[j] = res.raw.at(detail::qlen_trunc(res.raw, e));
448 for (std::size_t l = 0; l < d; ++l) {
449 std::vector<std::size_t> aa(d, 0);
452 res.cov(j, l) = res.cumulant.at(detail::qlen_trunc(res.cumulant, aa));