5#ifndef LINE_API_PFQN_NC_H
6#define LINE_API_PFQN_NC_H
235 "' is an asymptotic or Monte Carlo estimator formed in logarithms and "
236 "needs transcendental arithmetic. "
237 "Use 'ca', 'exact', 'recal', 'mva' or 'comom' for an exact constant.");
278 const std::size_t R = N.size();
292 res.
lG = -std::numeric_limits<double>::infinity();
296 throw InputError(
"pfqn_nc: L and N disagree on the class count");
298 const std::size_t M0 = L.
empty() ? 0 : L.
rows();
299 std::vector<T> lam(R, zero);
300 for (std::size_t r = 0; r < R && r < lambda.size(); ++r) lam[r] = lambda[r];
305 std::vector<std::size_t> ocl;
306 for (std::size_t r = 0; r < R; ++r)
307 if (N[r] < 0) ocl.push_back(r);
308 for (std::size_t i = 0; i < M0; ++i) {
310 for (std::size_t r = 0; r < R; ++r) u -= lam[r] * L(i, r);
318 for (std::size_t r = 0; r < R; ++r) Lw(i, r) = zero;
321 for (std::size_t r = 0; r < R; ++r) {
322 Lw(i, r) = L(i, r) / u;
323 Qopen(i, r) = lam[r] * Lw(i, r) / u;
328 std::vector<int> Nc(R, 0);
329 for (std::size_t r = 0; r < R; ++r) Nc[r] = N[r] > 0 ? N[r] : 0;
331 for (
int v : Nc) Ntot += v;
332 if (Ntot == 0)
return res;
334 const auto colsum = [&](
const Matrix<T>& A, std::size_t r) {
336 for (std::size_t i = 0; i < A.
rows(); ++i) s += A(i, r);
341 std::vector<std::size_t> nnz;
342 for (std::size_t r = 0; r < R; ++r)
343 if (Nc[r] > 0) nnz.push_back(r);
344 const std::size_t R1 = nnz.size();
347 std::vector<T> scalevec(R1, one);
349 for (std::size_t k = 0; k < R1; ++k) {
350 const std::size_t r = nnz[k];
352 for (std::size_t i = 0; i < M0; ++i)
353 if (Lw(i, r) > mx) mx = Lw(i, r);
354 for (std::size_t i = 0; i < Z1.
rows(); ++i)
355 if (Z(i, r) > mx) mx = Z(i, r);
356 if (mx > zero) scalevec[k] = mx;
357 for (std::size_t i = 0; i < M0; ++i) L1(i, k) = Lw(i, r) / scalevec[k];
358 for (std::size_t i = 0; i < Z1.
rows(); ++i) Z1(i, k) = Z(i, r) / scalevec[k];
362 for (std::size_t k = 0; k < R1; ++k)
363 Gscale *=
num_pow_int(scalevec[k],
static_cast<unsigned>(Nc[nnz[k]]));
369 double lGscale = 0.0;
371 for (std::size_t k = 0; k < R1; ++k)
372 lGscale +=
static_cast<double>(Nc[nnz[k]]) *
377 std::vector<std::size_t> demSt;
378 for (std::size_t i = 0; i < M0; ++i) {
380 for (std::size_t k = 0; k < R1; ++k) rs += L1(i, k);
381 if (rs > atol) demSt.push_back(i);
384 for (std::size_t a = 0; a < demSt.size(); ++a)
385 for (std::size_t k = 0; k < R1; ++k) L2(a, k) = L1(demSt[a], k);
386 const std::size_t M = demSt.size();
388 std::vector<int> N2(R1, 0);
389 for (std::size_t k = 0; k < R1; ++k) N2[k] = Nc[nnz[k]];
394 for (std::size_t k = 0; k < R1; ++k) {
396 for (std::size_t i = 0; i < Z1.
rows(); ++i) s += Z1(i, k);
397 if (Zag.
rows() > 0) Zag(0, k) = s;
402 const auto delayG = [&](
const std::vector<std::size_t>& cls) {
404 for (std::size_t k : cls) {
406 for (std::size_t i = 0; i < Z1.
rows(); ++i) zs += Z1(i, k);
407 g *=
num_pow_int(zs,
static_cast<unsigned>(N2[k])) /
418 bool have_measures =
false;
419 const auto attach_open = [&]() {
420 if (ocl.empty() || !have_measures)
return;
422 for (std::size_t i = 0; i < M0; ++i)
423 for (std::size_t r : ocl) res.
Q(i, r) = Qopen(i, r);
424 res.
X.assign(R, zero);
425 for (std::size_t r : ocl) res.
X[r] = lam[r];
427 const auto finish = [&](
const T& gcore) {
428 res.
G = Gscale * gcore;
435 const auto finish_log = [&](
double lgcore) {
436 res.
lG = lGscale + lgcore;
444 for (std::size_t i = 0; i < M; ++i)
445 for (std::size_t k = 0; k < R1; ++k) Lsum += L2(i, k);
447 if (M == 0 || !(Lsum > atol)) {
449 std::vector<std::size_t> all(R1);
450 for (std::size_t k = 0; k < R1; ++k) all[k] = k;
451 return finish(Ztot > atol ? delayG(all) : one);
453 if (M == 1 && !(Ztot > atol)) {
456 for (
int v : N2) tot += v;
458 for (std::size_t k = 0; k < R1; ++k)
459 g *=
num_pow_int(L2(0, k),
static_cast<unsigned>(N2[k])) /
463 if (!(Ztot > atol)) {
465 bool identical =
true;
466 for (std::size_t i = 1; i < M && identical; ++i)
467 for (std::size_t k = 0; k < R1; ++k)
468 if (L2(i, k) != L2(0, k)) {
474 for (
int v : N2) tot += v;
477 for (std::size_t k = 0; k < R1; ++k)
478 g *=
num_pow_int(L2(0, k),
static_cast<unsigned>(N2[k])) /
485 std::vector<std::size_t> zdem, nzdem;
486 for (std::size_t k = 0; k < R1; ++k) {
488 for (std::size_t i = 0; i < M; ++i) s += L2(i, k);
489 (s > atol ? nzdem : zdem).push_back(k);
491 const T Gzdem = zdem.empty() ? one : delayG(zdem);
495 std::vector<int> N3(nzdem.size(), 0);
496 for (std::size_t a = 0; a < nzdem.size(); ++a) {
497 for (std::size_t i = 0; i < M; ++i) L3(i, a) = L2(i, nzdem[a]);
498 for (std::size_t i = 0; i < Zag.
rows(); ++i) Z3(i, a) = Zag(i, nzdem[a]);
499 N3[a] = N2[nzdem[a]];
506 const auto attach_measures = [&](
const std::vector<T>& Xr,
const Matrix<T>& Qr) {
509 for (std::size_t a = 0; a < nzdem.size() && a < Xr.size(); ++a) {
510 const std::size_t r = nnz[nzdem[a]];
511 res.
X[r] = Xr[a] / scalevec[nzdem[a]];
512 for (std::size_t i = 0; i < M && i < Qr.rows(); ++i) res.
Q(demSt[i], r) = Qr(i, a);
516 const std::size_t Rc = nzdem.size();
518 for (std::size_t i = 0; i < Z3.
rows(); ++i)
519 for (std::size_t a = 0; a < Rc; ++a) Z3tot += Z3(i, a);
523 std::vector<T> Zv(Rc, zero);
524 for (std::size_t i = 0; i < Z3.
rows(); ++i)
525 for (std::size_t a = 0; a < Rc; ++a) Zv[a] += Z3(i, a);
526 std::vector<T> Nv(Rc, zero);
527 for (std::size_t a = 0; a < Rc; ++a) Nv[a] = num_traits<T>::from_int(N3[a]);
529 for (
int v : N3) Nsum3 += v;
537 const bool default_multi =
541 M == 1 && Z3tot > atol && Nsum3 >= 10000;
542 const bool estimator =
543 default_multi || default_big_repairman || method ==
NcMethod::Clw ||
564 ? std::string(
"default (the multi-station cub / le branch)")
571 const auto cub_budget_order = [&]() {
572 const double Cmax =
static_cast<double>(M * Rc) * 125000.0;
574 static_cast<int>(std::min<double>(std::ceil((Nsum3 - 1) / 2.0), 16.0));
577 while (order < maxorder) {
579 static_cast<double>(Rc) *
580 nck(
static_cast<int>(M) + 2 * (order + 1),
static_cast<int>(M) - 1);
581 if (tot + next > Cmax)
break;
589 for (std::size_t a = 0; a < Rc; ++a) Zsum += num_traits<T>::to_double(Zv[a]);
614 if (M > 1 && Nsum3 < 1000) {
618 pfqn_cub(L3, N3, Zv, cub_budget_order(), fineTol).lG));
629 if (L3.
rows() >= 10 && L3.
cols() > 1) {
630 bool closed = !Nv.empty();
632 for (std::size_t r = 0; r < Nv.size(); ++r) {
638 attach_measures(thin.
X, thin.
Q);
642 return finish_log(lgz +
650 const int order =
static_cast<int>(std::ceil((Nsum3 - 1) / 2.0));
678 std::vector<T> Dv(L3.
rows());
679 for (std::size_t i = 0; i < L3.
rows(); ++i) Dv[i] = L3(i, 0);
693 L3, Nv, Zv, method ==
NcMethod::LcUe ?
"ue" :
"mva", 1e-10, 1000);
694 attach_measures(thin.
X, thin.
Q);
739 attach_measures(
mc.X,
mc.Q);
743 return finish_log(lgz +
pfqn_comomrm(L3, N3, Z3, 1).lG);
772 std::vector<T> Lrow(Rc, zero);
773 for (std::size_t a = 0; a < Rc; ++a) Lrow[a] = L3(0, a);
794 return finish_log(lgz +
805 "pfqn_nc: the 'divdiff' method requires a model without think time, "
806 "which needs the integral form of Corollary 3.4. Use 'ca' or "
814 std::vector<T> Lcol(M, zero);
815 for (std::size_t i = 0; i < M; ++i) Lcol[i] = L3(i, 0);
831 for (std::size_t r = 0; r < Rc; ++r) Zm(0, r) = Zv[r];
874 res.
X.assign(R, zero);
876 for (std::size_t a = 0; a < Rc; ++a) {
877 const std::size_t r = nnz[nzdem[a]];
878 res.
X[r] =
mva.XN[a] / scalevec[nzdem[a]];
879 for (std::size_t i = 0; i < M; ++i) res.
Q(demSt[i], r) =
mva.QN(i, a);
882 have_measures =
true;
888 "pfqn_nc: RECAL is available only for models with zero think time; this model "
896 for (
int v : N3) tot += v;
897 if (M >= Rc || tot > 10 || Z3tot > atol) {
902 res.
method =
"exact/recal";
913 "pfqn_nc: the 'comom' method supports a single queueing station, but this "
914 "model has more. Use 'default', 'ca' or 'exact'.");
928 }
else if (!(Z3tot > atol)) {
931 for (
int v : N3) tot += v;
933 for (std::size_t a = 0; a < Rc; ++a)
934 g *=
num_pow_int(L3(0, a),
static_cast<unsigned>(N3[a])) /
948 return finish(Gzdem * gcore);
UnsupportedError(const std::string &what)
The exception types the port throws.
Dense matrix and non-owning view.
NcResult< T > pfqn_mci(const Matrix< T > &D, const std::vector< int > &N, const std::vector< T > &Z, std::size_t samples, MciVariant variant, McRng &rng)
Monte Carlo Integration estimate of the normalizing constant of a closed product-form network (Ross,...
NcResult< T > pfqn_recal(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &m0)
RECAL (REcursive CALculation) for the exact normalizing constant of a closed product-form network (Co...
BktResult< T > pfqn_bkt(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Knessl-Tier expansion with the Stirling-remainder correction (BKT).
RgfmcResult< T > pfqn_rgfmc(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const T &tol, std::size_t maxterms, const T &maxcancel)
Multiclass Recursion by Generating Functions (RGF), with think times.
std::mt19937_64 McRng
The generator type every Monte Carlo entry point in this tree accepts.
MvaResult< T > pfqn_mva(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &mi)
Exact Mean Value Analysis for closed product-form networks (Reiser and Lavenberg 1980).
AghqResult< T > pfqn_aghq(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, std::size_t q)
NcResult< T > pfqn_mmsample2(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, std::size_t samples, McRng &rng)
Sampled McKenna-Mitra integral form of the normalizing constant of a repairman (single-queue plus del...
const char * nc_method_name(NcMethod m)
PropfairResult< T > pfqn_propfair(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Proportionally fair allocation estimate of the normalizing constant (Schweitzer 1979; Walton,...
LektResult< T > pfqn_lekt(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
The common corrected asymptotic expansion (LE-KT), computed on the cheaper side.
NcMethod nc_method_of(const std::string &s)
Map a method name to its enum; throws UnsupportedError on an unknown one.
BkResult< T > pfqn_bk(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Birman-Kogan saddle point normalizing constant with bottleneck detection.
LsResult< T > pfqn_ls(const Matrix< T > &L0, const std::vector< T > &N, const std::vector< T > &Z, std::size_t I, McRng &rng)
Logistic-sampling estimate of the normalizing constant of a closed product-form network.
BkLcResult< T > pfqn_bklc(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, const std::string &method="mva", double tol=1e-10, int maxiter=1000)
Birman-Kogan load concealment algorithm (Algorithm 2).
constexpr double CUB_MAX_EVALS
GlobalConstants.CubMaxEvals: the integrand-evaluation budget above which pfqn_nc lowers the cubature ...
ComomResult< T > pfqn_comomrm(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, int m)
CoMoM (class-oriented method of moments) for the finite repairman model: one queueing station of mult...
void pfqn_nc_refuse(const std::string &method)
Refuse a method in an arithmetic it has no meaning in.
constexpr double MCMC_DEFAULT_BURNIN
Warm-up fraction discarded before accumulation starts.
MmintResult< T > pfqn_mmint2_gausslegendre(const std::vector< T > &L, const std::vector< T > &N, const std::vector< T > &Z, int m, std::size_t nodecap)
Gauss-Legendre form on [0, 1e6] (MATLAB pfqn_mmint2_gausslegendre).
BleResult< T > pfqn_ble(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Logistic expansion estimate of the normalizing constant, bias-corrected.
NcResult< T > pfqn_ca(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z)
Convolution algorithm for the exact normalizing constant of a closed product-form network (Buzen 1973...
PanaceaResult< T > pfqn_panacea(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, int terms)
PANACEA normal-usage asymptotic expansion of the normalizing constant (Ramakrishnan and Mitra,...
@ Imci
gamma = max(0.01, 1 - U), the MonteQueue 2.0 recommendation
@ Mci
gamma = 1/sqrt(max N) where U > 0.9, else 1 - U
RgfResult< T > pfqn_rgf(const std::vector< T > &L, int N, const T &Z)
Recursion by Generating Functions (RGF) for the normalizing constant of a SINGLE-CLASS closed product...
ClwResult< T > pfqn_clw(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const std::vector< long > &m, const ClwOptions &opt)
Choudhury-Leung-Whitt normalization constant by numerical inversion of the generating function (JACM ...
constexpr std::size_t MCMC_DEFAULT_BATCHES
Schmeiser (1982), the batch count used in the tables of the paper.
BkResult< T > pfqn_bkue(const std::vector< T > &L, const T &N, const T &Z)
Birman-Kogan uniform (van der Waerden) expansion for a single chain.
NcMethod
The methods this port dispatches, one per compute_norm_const case.
@ Rgf
recursion by generating functions; residues beyond one class
@ Adaptive
the reference groups 'adaptive' with 'default'
@ Gm
the reference's alias of 'cub'
@ Bkt
KT minus the exact Stirling remainder of each Laplaced class (BKT).
@ Bkue
Birman-Kogan uniform (van der Waerden) expansion, single chain.
@ Aghq
adaptive Gauss-Hermite over the simplex; q=1 is Le
@ Lekt
the estimator Ble and Bkt both compute, on the cheaper side
@ Gleint
the reference's alias of 'mmint2'
@ Ger
residue closed form; free in the eliminated class populations
@ Mcmc
Chen-O'Cinneide regularization; supplies X and Q, never a constant.
@ Bk
Birman-Kogan saddle point with bottleneck detection.
@ Ble
LE plus the empirical eps->0 correction.
@ Divdiff
divided-difference closed form; no think time, no load dependence
@ Lc
Birman-Kogan Algorithm 2, single chain subproblems by MVA.
@ LcUe
Algorithm 2 with the uniform expansion as the single chain solver.
McmcResult< T > pfqn_mcmc(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const std::vector< double > &s, std::size_t samples, std::size_t nbatches, double burnin, McRng &rng)
Chen-O'Cinneide REGULARIZATION: a Markov chain Monte Carlo estimator of the class throughputs X(r) = ...
KtResult< T > pfqn_kt(const Matrix< T > &L0, const std::vector< T > &N0, const std::vector< T > &Z0)
Knessl-Tier asymptotic expansion of the normalizing constant.
ExplicitResult< T > pfqn_explicit(const Matrix< T > &L, const std::vector< int > &N, double tol=std::numeric_limits< double >::epsilon(), const std::string &method="auto", double maxloss=std::numeric_limits< double >::infinity())
Explicit closed-form normalizing constant of a multiclass closed network.
LeResult< T > pfqn_le(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Logistic expansion estimate of the normalizing constant.
double pfqn_cub_evals(int M, int order, double Zsum)
Integrand-evaluation count of pfqn_cub, and the budget pfqn_nc prices it against.
NcResult< T > pfqn_is(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, std::size_t samples, McRng &rng)
Importance-sampling estimate of the normalizing constant of a closed LOAD-INDEPENDENT product-form ne...
NcResult< T > pfqn_gerasimov(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, double tol=1e-12, std::size_t maxterms=200000)
Exact normalizing constant of a closed multiclass product-form network by ITERATED RESIDUES of its ra...
CubResult< T > pfqn_cub(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, int order, const T &atol)
Normalizing constant by Grundmann-Moeller cubature over the simplex.
NcDispatchResult< T > pfqn_nc(const std::vector< T > &lambda, const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, NcMethod method, const T &atol, const NcOptions &nopt)
Normalizing constant of a product-form queueing network: the dispatcher.
Conservation laws of a layered queueing network, enumerated from its structure.
T num_factorial(unsigned n)
Factorial as a value of T.
T num_pow_int(const T &base, unsigned e)
Integer power, valid in any field (no transcendental requirement).
double nck(int n, int k)
Binomial coefficient with a thread-local memo table (mp_pfqn util/nck.c).
Number-type abstraction for the templated API port.
Adaptive Gauss-Hermite quadrature of the simplex factor of the McKenna-Mitra integral.
Birman-Kogan asymptotic evaluation of closed networks with many stations.
Knessl-Tier expansion with the Stirling-remainder correction (BKT).
Logistic expansion with the eps->0 bias correction (BLE).
Convolution algorithm for the exact normalizing constant of a closed product-form network (Buzen 1973...
Choudhury-Leung-Whitt normalization constant by numerical inversion of the generating function (JACM ...
CoMoM (class-oriented method of moments) for the finite repairman model: one queueing station of mult...
Normalizing constant by Grundmann-Moeller cubature over the simplex.
Integrand-evaluation count of pfqn_cub, and the budget pfqn_nc prices it against.
Explicit closed-form normalizing constant of a multiclass closed network.
Gerasimov's residue (closed-form) normalizing constant, generalized to R classes.
Importance-sampling estimate of the normalizing constant of a closed LOAD-INDEPENDENT product-form ne...
Knessl-Tier asymptotic expansion of the normalizing constant.
Logistic expansion (LE) asymptotic approximation of the normalizing constant of a closed product-form...
The common corrected asymptotic expansion (LE-KT), computed on the cheaper side.
Logistic-sampling estimate of the normalizing constant of a closed product-form network.
Monte Carlo Integration estimate of the normalizing constant of a closed product-form network (Ross,...
Chen-O'Cinneide REGULARIZATION: a Markov chain Monte Carlo estimator of the class throughputs X(r) = ...
McKenna-Mitra integral form of the normalizing constant of a repairman model (one queueing station,...
Sampled McKenna-Mitra integral form of the normalizing constant of a repairman (single-queue plus del...
Exact Mean Value Analysis for closed product-form networks (Reiser and Lavenberg 1980).
PANACEA normal-usage asymptotic expansion of the normalizing constant (Ramakrishnan and Mitra,...
Proportionally fair allocation estimate of the normalizing constant (Schweitzer 1979; Walton,...
RECAL (REcursive CALculation) for the exact normalizing constant of a closed product-form network (Co...
Recursion by Generating Functions (RGF) for the normalizing constant of a SINGLE-CLASS closed product...
Multiclass Recursion by Generating Functions (RGF), with think times.
Population-vector enumeration and combinatorics.
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
Return value of pfqn_bklc.
Return value of pfqn_explicit, mirroring [lG, G, method, lossDigits].
std::string method
expression used, "distinct" (Eq. 15) or "repeated" (Eq. 16)
T lG
logarithm of the normalizing constant
Estimates of pfqn_mcmc together with their batch-means intervals.
std::vector< T > X
(R) per-class throughput, empty when not produced
std::string method
the algorithm actually used
Matrix< T > Q
(M x R) queue lengths, empty when not produced
bool valid
False when the METHOD DECLINED THE MODEL, which is the reference's lG = []: pana outside normal usage...
T G
normalizing constant, exact when the method is
The options fields compute_norm_const reads beyond the method itself.
double mcmc_burnin
options.config.mcmc_burnin: warm-up fraction pfqn_mcmc discards
unsigned long seed
SolverOptions('NC').seed.
std::size_t mcmc_batches
options.config.mcmc_batches: batches pfqn_mcmc splits its run into
std::size_t aghq_nodes
options.config.aghq_nodes: nodes per simplex direction of the adaptive Gauss-Hermite rule.
std::size_t samples
SolverOptions('NC').samples.
double tol
handed to pfqn_comomrm
Return value of pfqn_panacea, mirroring [Gn, lGn].
bool normalUsage
false where MATLAB returns NaN (min alpha < 0)