25#include <initializer_list>
112std::size_t depth(
const Args& a,
const char* fn, std::initializer_list<Pos> keys) {
113 const std::vector<Pos> k(keys);
115 for (std::size_t i = 0; i < k.size(); ++i)
116 if (a.has(k[i].key)) d = i + 1;
117 for (std::size_t i = 0; i + 1 < d; ++i) {
118 if (k[i].fillable || a.has(k[i].key))
continue;
120 for (std::size_t j = d; j-- > i + 1;)
121 if (a.has(k[j].key)) later = k[j].key;
122 throw InputError(std::string(fn) +
": '" + later +
"' is given but '" + k[i].key +
123 "' is not; the C++ port takes '" + k[i].key +
"' positionally before '" +
124 later +
"', so it cannot be left to its default while '" + later +
125 "' is set. Give '" + k[i].key +
"' as well.");
135bool long_form(
const Args& a,
const char* fn, std::initializer_list<const char*> triggers,
136 std::initializer_list<const char*> needed) {
138 for (
const char* t : triggers)
143 if (trig.empty())
return false;
144 for (
const char* n : needed)
146 throw InputError(std::string(fn) +
": '" + trig +
"' selects the long form of the C++ "
147 "port, which has no default for '" + n +
"'; give '" + n +
148 "' as well, or drop '" + trig +
"' to use the port's own defaults.");
153int sched_code(
const Json& e,
const std::string& where) {
155 throw InputError(where +
": a scheduling entry must be one of \"PS\", \"FCFS\" or \"INF\", got " +
156 std::string(e.type_name()));
157 std::string s = e.get<std::string>();
158 for (
char& c : s) c =
static_cast<char>(std::toupper(
static_cast<unsigned char>(c)));
159 if (s ==
"PS")
return 0;
160 if (s ==
"FCFS")
return 1;
161 if (s ==
"INF")
return 2;
162 throw InputError(where +
": unknown scheduling strategy '" + e.get<std::string>() +
163 "'; expected \"PS\", \"FCFS\" or \"INF\"");
168std::vector<E> sched_vector(
Args& a,
const char* key, E ps, E fcfs, E inf) {
170 const Json* j = a.opt(key);
172 const std::string where = std::string(
"'") + key +
"'";
173 std::vector<Json> flat;
175 for (
const Json& e : *j) flat.push_back(e);
178 for (
const Json& e : flat) {
179 const int c = sched_code(e, where);
180 out.push_back(c == 0 ? ps : (c == 1 ? fcfs : inf));
185std::vector<pfqn::AmvaSched> amva_sched(
Args& a,
const char* key) {
189std::vector<pfqn::SchedStrategy> lin_sched(
Args& a,
const char* key) {
195double real_option(
Args& a,
const char* key,
bool cn) {
196 const Json& j = a.get(key);
197 if (cn && j.is_string()) {
198 std::string s = j.get<std::string>();
199 for (
char& c : s) c =
static_cast<char>(std::tolower(
static_cast<unsigned char>(c)));
200 if (s ==
"cn")
return std::nan(
"");
206int int_arg(
Args& a,
const char* key) {
return a.required_integer(key); }
209std::vector<std::size_t> index_list(
const Json& j,
const std::string& where) {
211 std::vector<std::size_t> out;
212 out.reserve(v.size());
214 if (x < 0)
throw InputError(where +
": an index cannot be negative, got " + std::to_string(x));
215 out.push_back(
static_cast<std::size_t
>(x));
220std::vector<std::size_t> indices(
Args& a,
const char* key) {
221 return index_list(a.get(key), std::string(
"'") + key +
"'");
224std::vector<std::size_t> indices_or_empty(
Args& a,
const char* key) {
225 const Json* j = a.opt(key);
226 return j ? index_list(*j, std::string(
"'") + key +
"'") : std::vector<std::size_t>();
230std::vector<std::vector<std::size_t> > index_lists(
const Json& j,
const std::string& where,
232 std::vector<std::vector<std::size_t> > out;
233 if (!j.is_array())
throw InputError(where +
": expected an array of index arrays");
235 for (
const Json& e : j)
236 if (e.is_array()) nested =
true;
237 if (!nested && !j.empty()) {
238 if (!flat_is_one)
throw InputError(where +
": expected an array of index arrays");
239 out.push_back(index_list(j, where));
242 for (std::size_t b = 0; b < j.size(); ++b) {
243 if (!j[b].is_array())
244 throw InputError(where +
": entry " + std::to_string(b) +
" must be an array");
245 out.push_back(index_list(j[b], where +
"[" + std::to_string(b) +
"]"));
251Matrix<int> int_matrix(
Args& a,
const char* key) {
252 const Json& j = a.get(key);
253 const std::string where = std::string(
"'") + key +
"'";
254 if (j.is_array() && !j.empty() && j[0].is_array()) {
255 const std::size_t rows = j.size(), cols = j[0].size();
256 Matrix<int> m(rows, cols, 0);
257 for (std::size_t i = 0; i < rows; ++i) {
258 if (!j[i].is_array() || j[i].size() != cols)
259 throw InputError(where +
": row " + std::to_string(i) +
" has the wrong length");
261 for (std::size_t k = 0; k < cols; ++k) m(i, k) = r[k];
266 Matrix<int> m(1, r.size(), 0);
267 for (std::size_t k = 0; k < r.size(); ++k) m(0, k) = r[k];
272std::vector<int> mixed_population(
Args& a,
const char* key) {
273 const Json& j = a.get(key);
274 const std::string where = std::string(
"'") + key +
"'";
275 std::vector<int> out;
277 if (std::isinf(d) && d > 0) {
281 if (d != std::floor(d) || d < 0)
282 throw InputError(where +
": a closed-class population must be a non-negative integer");
283 out.push_back(
static_cast<int>(d));
289std::vector<bool> bool_vector(
const Json& j,
const std::string& where) {
290 std::vector<bool> out;
291 std::vector<Json> flat;
293 for (
const Json& e : j) flat.push_back(e);
296 for (
const Json& e : flat) {
297 if (e.is_boolean()) {
298 out.push_back(e.get<
bool>());
302 if (v.size() != 1 || (v[0] != 0 && v[0] != 1))
303 throw InputError(where +
": entries must be true, false, 0 or 1");
304 out.push_back(v[0] != 0);
309Json encode_index_list(
const std::vector<std::size_t>& v) {
310 Json a = Json::array();
311 for (std::size_t x : v) a.push_back(
static_cast<std::uint64_t
>(x));
317T exp_of_log(
Args& a,
const char* key) {
318 if constexpr (num_traits<T>::has_transcendental) {
320 const T l = a.number<T>(key);
324 std::string(
"'") + key +
"' is a logarithm, and exp() is not in the exact "
325 "rational field; omit it to have the port compute G(N) exactly, or rerun "
326 "with --arith double or --arith real:<digits>.");
335Json amva_results(
const pfqn::AmvaResult<T>& r,
const char* itkey) {
342 out[
"converged"] = r.converged;
348Json lin_results(
const pfqn::LinearizerResult<T>& r,
const char* q,
const char* u,
const char* w,
349 const char* c,
const char* x) {
356 out[
"totiter"] = r.totiter;
361Json lin_results(
const pfqn::LinearizerResult<T>& r) {
362 return lin_results(r,
"Q",
"U",
"W",
"C",
"X");
365template <
class G,
class L>
366Json g_lg(
const G& g,
const L& lg,
const char* gk =
"G",
const char* lk =
"lG") {
377struct OpCycletOfree {
378 static Json run(Args& a) {
379 const std::vector<double> v = a.vector<
double>(
"v");
380 const std::vector<double> mu = a.vector<
double>(
"mu");
381 const std::size_t N = a.count(
"N");
382 const std::vector<std::vector<std::size_t> > paths =
383 index_lists(a.get(
"path"),
"'path'",
true);
384 const std::vector<double> tset = a.vector<
double>(
"tset");
385 pfqn::CycletResult r;
386 const Json* oj = a.opt(
"options");
391 Args o(*oj,
"pfqn_cyclet_ofree options");
392 const std::size_t d = depth(o,
"pfqn_cyclet_ofree options",
393 {{
"method",
false}, {
"nmom",
false}, {
"pathprob",
true},
394 {
"lti_method",
false}, {
"tol",
false}});
395 const std::string method = o.has(
"method") ? o.text(
"method",
"") : std::string();
396 const std::size_t nmom = o.has(
"nmom") ? o.count(
"nmom") : 0;
397 const std::vector<double> pathprob = o.vector_or_empty<
double>(
"pathprob");
398 const std::string lti = o.has(
"lti_method") ? o.text(
"lti_method",
"") : std::string();
399 const double tol = o.has(
"tol") ? o.number<
double>(
"tol") : 0.0;
420 Json info = Json::array();
421 for (
const pfqn::CycletPathInfo& p : r.info) {
423 e[
"method"] = p.method;
425 e[
"path"] = encode_index_list(p.path);
435 static Json run(Args& a) {
436 const Matrix<T>
QN = a.matrix<T>(
"QN");
437 const Matrix<T>
UN = a.matrix<T>(
"UN");
438 const Matrix<T> CN = a.matrix<T>(
"CN");
439 std::vector<std::size_t> mapping = indices(a,
"mapping");
440 const std::size_t M = a.count(
"M_original");
443 if (mapping.size() < M)
444 throw InputError(
"pfqn_expand: mapping has " + std::to_string(mapping.size()) +
445 " entries, fewer than M_original = " + std::to_string(M));
457Json explicit_results(
const pfqn::ExplicitResult<T>& r) {
461 out[
"method"] = r.method;
462 out[
"lossDigits"] = r.lossDigits;
463 out[
"valid"] = r.valid;
469 static Json run(Args& a) {
470 const Matrix<T> L = a.matrix<T>(
"L");
471 const std::vector<int> N = a.ints(
"N");
472 const std::size_t d =
473 depth(a,
"pfqn_explicit", {{
"tol",
false}, {
"method",
false}, {
"maxloss",
false}});
474 const double tol = a.has(
"tol") ? a.number<
double>(
"tol") : 0.0;
475 const std::string method = a.text(
"method",
"");
476 const double maxloss = a.has(
"maxloss") ? a.number<
double>(
"maxloss") : 0.0;
489 static Json run(Args& a) {
490 const Matrix<T> L = a.matrix<T>(
"L");
491 const std::vector<int> N = a.ints(
"N");
492 const Matrix<T> mu = a.matrix<T>(
"mu");
493 const std::size_t d =
494 depth(a,
"pfqn_explicit_ld", {{
"tol",
false}, {
"method",
false}, {
"maxloss",
false}});
495 const double tol = a.has(
"tol") ? a.number<
double>(
"tol") : 0.0;
496 const std::string method = a.text(
"method",
"");
497 const double maxloss = a.has(
"maxloss") ? a.number<
double>(
"maxloss") : 0.0;
511 static Json run(Args& a) {
512 const Matrix<T> L = a.matrix<T>(
"L");
513 const std::vector<int> N = a.ints(
"N");
514 const bool hasZ = a.has(
"Z"), hasMu = a.has(
"mu");
515 const Matrix<T> Z = a.matrix_or_empty<T>(
"Z");
516 const Matrix<T> mu = a.matrix_or_empty<T>(
"mu");
517 a.unsupported(
"options",
"the C++ port of pfqn_divdiff_ld takes no solver options");
525 out[
"lossDigits"] = r.lossDigits;
536 std::vector<pfqn::AmvaSched> type;
545AmvaArgs<T> read_amva(
Args& a,
const char* fn,
bool cn, std::initializer_list<Pos> extra) {
547 s.L = a.matrix<T>(
"L");
548 s.N = a.vector<T>(
"N");
550 s.Z = a.vector_or_empty<T>(
"Z");
551 std::vector<Pos> keys = {{
"tol",
false}, {
"maxiter",
false}, {
"QN0",
true}};
552 keys.insert(keys.end(), extra.begin(), extra.end());
554 if (keys.size() == 3)
555 s.d = depth(a, fn, {{
"tol",
false}, {
"maxiter",
false}, {
"QN0",
true}});
557 s.d = depth(a, fn, {{
"tol",
false}, {
"maxiter",
false}, {
"QN0",
true}, keys[3]});
558 s.longf = s.d > 0 || a.has(
"type");
559 s.type = amva_sched(a,
"type");
560 s.tol = a.has(
"tol") ? real_option(a,
"tol", cn) : 0.0;
561 s.maxiter = a.has(
"maxiter") ? a.count(
"maxiter") : 0;
562 s.QN0 = a.matrix_or_empty<T>(
"QN0");
568 static Json run(Args& a) {
569 AmvaArgs<T> s = read_amva<T>(a,
"pfqn_bs",
true, {});
571 pfqn::AmvaResult<T> r;
581 r =
pfqn::pfqn_bs(s.L, s.N, s.Z, s.type, s.tol, s.maxiter, s.QN0);
582 return amva_results(r,
"it");
588 static Json run(Args& a) {
589 AmvaArgs<T> s = read_amva<T>(a,
"pfqn_lcp",
false, {});
591 pfqn::AmvaResult<T> r;
601 r =
pfqn::pfqn_lcp(s.L, s.N, s.Z, s.type, s.tol, s.maxiter, s.QN0);
602 return amva_results(r,
"it");
607 std::string v = a.text(
"variant",
"");
608 for (
char& c : v) c =
static_cast<char>(std::tolower(
static_cast<unsigned char>(c)));
611 throw InputError(
"pfqn_chow: unknown variant '" + v +
"'; expected \"forward\" or \"backward\"");
616 static Json run(Args& a) {
617 AmvaArgs<T> s = read_amva<T>(a,
"pfqn_chow",
false, {{
"variant",
false}});
618 const bool hasVariant = a.has(
"variant");
621 pfqn::AmvaResult<T> r;
622 if (!s.longf && !hasVariant)
633 r =
pfqn::pfqn_chow(s.L, s.N, s.Z, s.type, s.tol, s.maxiter, s.QN0, variant);
634 return amva_results(r,
"it");
640 static Json run(Args& a) {
641 const std::vector<T> N = a.vector<T>(
"N");
651 static Json run(Args& a) {
652 const Matrix<T> L = a.matrix<T>(
"L");
653 const std::vector<T> N = a.vector<T>(
"N");
654 const bool hasZ = a.has(
"Z");
655 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
656 const std::size_t d = depth(a,
"pfqn_aql", {{
"TOL",
false}, {
"MAXITER",
false}});
657 const double tol = a.has(
"TOL") ? a.number<
double>(
"TOL") : 0.0;
658 const std::size_t maxiter = a.has(
"MAXITER") ? a.count(
"MAXITER") : 0;
659 a.unsupported(
"QN0",
"the C++ port of pfqn_aql takes no warm start; omit QN0");
661 pfqn::AmvaResult<T> r;
668 return amva_results(r,
"numIters");
675 std::vector<pfqn::SchedStrategy> type;
682LinArgs<T> read_lin(
Args& a,
bool cn) {
684 s.type = lin_sched(a,
"type");
685 if (a.has(
"tol")) s.tol = real_option(a,
"tol", cn);
686 if (a.has(
"maxiter")) s.maxiter =
static_cast<int>(a.count(
"maxiter"));
687 s.QN0 = a.matrix_or_empty<T>(
"QN0");
693 static Json run(Args& a) {
694 const Matrix<T> L = a.matrix<T>(
"L");
695 const std::vector<int> N = a.ints(
"N");
696 const bool hasZ = a.has(
"Z");
697 const Matrix<T> Z = a.matrix_or_empty<T>(
"Z");
698 const bool lf = long_form(a,
"pfqn_linearizer", {
"type",
"tol",
"maxiter",
"QN0"},
700 const LinArgs<T> s = read_lin<T>(a,
true);
707struct OpLinearizerms {
709 static Json run(Args& a) {
710 const Matrix<T> L = a.matrix<T>(
"L");
711 const std::vector<int> N = a.ints(
"N");
712 const Matrix<T> Z = a.matrix_or_empty<T>(
"Z");
713 const std::vector<int> nservers = a.ints(
"nservers");
714 const bool lf = long_form(a,
"pfqn_linearizerms", {
"type",
"tol",
"maxiter",
"QN0"},
716 const LinArgs<T> s = read_lin<T>(a,
false);
718 const pfqn::LinearizerResult<T> r =
721 return lin_results(r,
"Q",
"U",
"R",
"C",
"X");
727 static Json run(Args& a) {
728 const Matrix<T> L = a.matrix<T>(
"L");
729 const std::vector<int> N = a.ints(
"N");
730 const Matrix<T> Z = a.matrix_or_empty<T>(
"Z");
731 const std::vector<int> nservers = a.ints(
"nservers");
732 const bool lf = long_form(a,
"pfqn_conwayms", {
"type",
"tol",
"maxiter",
"QN0"},
734 const LinArgs<T> s = read_lin<T>(a,
false);
736 const pfqn::LinearizerResult<T> r =
739 return lin_results(r,
"Q",
"U",
"R",
"C",
"X");
744 std::string m = a.text(
"method",
"");
745 for (
char& c : m) c =
static_cast<char>(std::tolower(
static_cast<unsigned char>(c)));
749 throw InputError(
"pfqn_linearizermx: unknown method '" + m +
750 "'; expected \"lin\", \"gflin\" or \"egflin\"");
753struct OpLinearizermx {
755 static Json run(Args& a) {
756 const std::vector<T> lambda = a.vector<T>(
"lambda");
757 const Matrix<T> L = a.matrix<T>(
"L");
758 const std::vector<int> N = mixed_population(a,
"N");
759 const Matrix<T> Z = a.matrix_or_empty<T>(
"Z");
760 const std::vector<int> nservers = a.ints(
"nservers");
761 const bool lf = long_form(a,
"pfqn_linearizermx", {
"type",
"tol",
"maxiter",
"QN0"},
762 {
"tol",
"maxiter",
"method"});
763 const LinArgs<T> s = read_lin<T>(a,
false);
764 const bool hasMethod = a.has(
"method");
768 pfqn::LinearizerResult<T> r;
776 return lin_results(r,
"QN",
"UN",
"WN",
"CN",
"XN");
780struct OpGflinearizer {
782 static Json run(Args& a) {
783 const Matrix<T> L = a.matrix<T>(
"L");
784 const std::vector<int> N = a.ints(
"N");
785 const Matrix<T> Z = a.matrix_or_empty<T>(
"Z");
786 const bool lf = long_form(a,
"pfqn_gflinearizer", {
"type",
"tol",
"maxiter",
"QN0"},
788 const LinArgs<T> s = read_lin<T>(a,
true);
789 const T alpha = a.number<T>(
"alpha");
798struct OpEgflinearizer {
800 static Json run(Args& a) {
801 const Matrix<T> L = a.matrix<T>(
"L");
802 const std::vector<int> N = a.ints(
"N");
803 const Matrix<T> Z = a.matrix_or_empty<T>(
"Z");
804 const bool lf = long_form(a,
"pfqn_egflinearizer",
805 {
"type",
"tol",
"maxiter",
"QN0",
"npasses"}, {
"tol",
"maxiter"});
806 const LinArgs<T> s = read_lin<T>(a,
true);
807 const std::vector<T> alpha = a.vector<T>(
"alpha");
808 const bool hasNp = a.has(
"npasses");
809 const int npasses = hasNp ? int_arg(a,
"npasses") : 0;
822 static Json run(Args& a) {
823 const Matrix<T> L = a.matrix<T>(
"L");
824 const std::vector<int> N = a.ints(
"N");
825 const bool hasZ = a.has(
"Z");
826 const Matrix<T> Z = a.matrix_or_empty<T>(
"Z");
827 const bool lf = long_form(a,
"pfqn_dmlin", {
"type",
"tol",
"maxiter",
"QN0",
"npasses"},
829 const LinArgs<T> s = read_lin<T>(a,
false);
830 const bool hasNp = a.has(
"npasses");
831 const int npasses = hasNp ? int_arg(a,
"npasses") : 0;
837 return lin_results(
pfqn::pfqn_dmlin(L, N, Z, s.type, s.tol, s.maxiter, s.QN0));
843 static Json run(Args& a) {
844 const std::vector<T> n = a.vector<T>(
"n");
845 const Matrix<T> lldscaling = a.matrix_or_empty<T>(
"lldscaling");
846 const bool hasC = a.has(
"nservers");
847 const std::vector<double> nservers = a.vector_or_empty<
double>(
"nservers");
858 static Json run(Args& a) {
859 const Matrix<T> L = a.matrix<T>(
"L");
860 const std::vector<int> N = a.ints(
"N");
861 const Matrix<T> Z = a.matrix_or_empty<T>(
"Z");
862 const Matrix<T> mu = a.matrix<T>(
"mu");
863 a.unsupported(
"options",
"the C++ port of pfqn_comomrm_ld takes no solver options "
864 "(MATLAB reads options.tol there)");
867 Json out = g_lg(r.G, r.lG);
875 static Json run(Args& a) {
876 const Matrix<T> L = a.matrix<T>(
"L");
877 const int N = int_arg(a,
"N");
878 const Matrix<T> mu = a.matrix<T>(
"mu");
879 a.unsupported(
"options",
"the C++ port of pfqn_gldsingle takes no solver options");
882 return g_lg(r.G, r.lG);
888 static Json run(Args& a) {
889 const Matrix<T> L = a.matrix<T>(
"L");
890 const int N = int_arg(a,
"N");
891 const Matrix<T> mu = a.matrix<T>(
"mu");
892 a.unsupported(
"options",
"the C++ port of pfqn_lldsingle takes no solver options");
895 return g_lg(r.G, r.lG);
901 static Json run(Args& a) {
902 const Matrix<T> L = a.matrix<T>(
"L");
903 const std::vector<int> N = a.ints(
"N");
904 const bool hasMu = a.has(
"mu");
905 const Matrix<T> mu = a.matrix_or_empty<T>(
"mu");
906 a.unsupported(
"options",
"the C++ port of pfqn_lld takes no solver options");
909 Json out = g_lg(r.G, r.lG);
917 static Json run(Args& a) {
918 const Matrix<int> n = int_matrix(a,
"n");
919 const Matrix<T> L = a.matrix<T>(
"L");
920 const std::vector<int> N = a.ints(
"N");
921 const Matrix<T> Z = a.matrix_or_empty<T>(
"Z");
922 const bool hasG = a.has(
"lGN");
923 const T G = hasG ? exp_of_log<T>(a,
"lGN") : num_traits<T>::from_int(0);
928 std::vector<int> m(n.rows());
929 for (std::size_t i = 0; i < n.rows(); ++i) m[i] = n(i, 0);
930 p = hasG ? pfqn::pfqn_joint_total(m, L, N, Z, G) : pfqn::pfqn_joint_total(m, L, N, Z);
932 p = hasG ? pfqn::pfqn_joint(n, L, N, Z, G) : pfqn::pfqn_joint(n, L, N, Z);
942 static Json run(Args& a) {
943 const std::vector<int> n = a.ints(
"n");
944 const Matrix<T> L = a.matrix<T>(
"L");
945 const std::vector<int> N = a.ints(
"N");
946 const std::vector<std::size_t> infset = indices_or_empty(a,
"infset");
947 const bool hasG = a.has(
"lGN");
948 const T G = hasG ? exp_of_log<T>(a,
"lGN") : num_traits<T>::from_int(0);
949 const bool hasE = a.has(
"engine");
950 const std::string engine = a.text(
"engine",
"");
961 if constexpr (num_traits<T>::has_transcendental) {
965 out[
"lpjoint"] = std::log(num_traits<T>::to_double(p));
973 static Json run(Args& a) {
974 const std::vector<T> alpha = a.vector<T>(
"alpha");
975 const std::vector<T> beta = a.vector<T>(
"beta");
976 const std::vector<int> N = a.ints(
"N");
988 static Json run(Args& a) {
989 const std::vector<T> alpha = a.vector<T>(
"alpha");
990 const std::vector<T> beta = a.vector<T>(
"beta");
991 const std::vector<int> N = a.ints(
"N");
1005 static Json run(Args& a) {
1006 const std::vector<T> alpha = a.vector<T>(
"alpha");
1007 const std::vector<T> beta = a.vector<T>(
"beta");
1008 const std::vector<int> N = a.ints(
"N");
1018 static Json run(Args& a) {
1019 const std::vector<T> lambda = a.vector<T>(
"lambda");
1020 const Matrix<T> D = a.matrix<T>(
"D");
1021 const Matrix<T> mu = a.matrix<T>(
"mu");
1035 static Json run(Args& a) {
1036 const std::vector<T> L = a.vector<T>(
"L");
1037 const int N = int_arg(a,
"N");
1038 const T Z = a.number<T>(
"Z");
1039 const bool hasLevel = a.has(
"level");
1040 const int level = hasLevel ? int_arg(a,
"level") : 0;
1052 static Json run(Args& a) {
1053 const Matrix<T> L = a.matrix<T>(
"L");
1054 const std::vector<int> N = a.ints(
"N");
1055 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
1056 const bool lf = long_form(a,
"pfqn_cub", {
"order",
"atol"}, {
"order",
"atol"});
1057 const int order = lf ? int_arg(a,
"order") : 0;
1058 const T atol = lf ? a.number<T>(
"atol") : num_traits<T>::from_int(0);
1061 return g_lg(r.G, r.lG,
"Gn",
"lGn");
1067 static Json run(Args& a) {
1068 const Matrix<T> L = a.matrix<T>(
"L");
1069 const std::vector<int> N = a.ints(
"N");
1070 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
1071 const bool hasMu = a.has(
"mu");
1072 const Matrix<T> mu = a.matrix_or_empty<T>(
"mu");
1077 Json st = Json::array();
1078 for (
const std::vector<int>& s : r.states) st.push_back(
encode_ints(s));
1091 static Json run(Args& a) {
1092 const Matrix<T> alpha = a.matrix<T>(
"alpha");
1093 const bool hasC = a.has(
"c");
1094 const std::vector<T> c = a.vector_or_empty<T>(
"c");
1106 static Json run(Args& a) {
1107 const Matrix<T> L = a.matrix<T>(
"L");
1108 const std::vector<int> N = a.ints(
"N");
1117#define LINE_PFQN_A_LNZ(Name, fn, gk, lk) \
1119 template <class T> \
1120 static Json run(Args& a) { \
1121 const Matrix<T> L = a.matrix<T>("L"); \
1122 const std::vector<T> N = a.vector<T>("N"); \
1123 const bool hasZ = a.has("Z"); \
1124 const std::vector<T> Z = a.vector_or_empty<T>("Z"); \
1126 const auto r = hasZ ? pfqn::fn(L, N, Z) : pfqn::fn(L, N); \
1127 return g_lg(r.G, r.lG, gk, lk); \
1134#undef LINE_PFQN_A_LNZ
1138 static Json run(Args& a) {
1139 const Matrix<T> L = a.matrix<T>(
"L");
1140 const std::vector<T> N = a.vector<T>(
"N");
1141 const bool hasZ = a.has(
"Z");
1142 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
1145 Json out = g_lg(r.G, r.lG);
1154 static Json run(Args& a) {
1155 const Matrix<T> L = a.matrix<T>(
"L");
1156 const std::vector<T> N = a.vector<T>(
"N");
1157 const bool hasZ = a.has(
"Z");
1158 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
1161 Json out = g_lg(r.G, r.lG,
"Gn",
"lGn");
1162 out[
"route"] = r.route;
1169 static Json run(Args& a) {
1170 const Matrix<T> L = a.matrix<T>(
"L");
1171 const std::vector<T> N = a.vector<T>(
"N");
1172 const std::size_t d = depth(a,
"pfqn_aghq", {{
"Z",
true}, {
"q",
false}});
1173 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
1174 const std::size_t q = a.has(
"q") ? a.count(
"q") : 0;
1176 pfqn::LeResult<T> r;
1183 return g_lg(r.G, r.lG,
"Gn",
"lGn");
1189 static Json run(Args& a) {
1190 const std::vector<T> L = a.vector<T>(
"L");
1191 const std::vector<T> N = a.vector<T>(
"N");
1192 const std::vector<T> Z = a.vector<T>(
"Z");
1202 static Json run(Args& a) {
1203 const std::vector<T> L = a.vector<T>(
"L");
1204 const T N = a.number<T>(
"N");
1205 const T Z = a.number<T>(
"Z");
1206 const bool lf = long_form(a,
"pfqn_ldbcmp", {
"c",
"tol"}, {
"c",
"tol"});
1207 const std::vector<T> c = a.vector_or_empty<T>(
"c");
1208 const T tol = lf ? a.number<T>(
"tol") : num_traits<T>::from_int(0);
1215 out[
"applicable"] = r.applicable;
1222 static Json run(Args& a) {
1223 const Matrix<T> D = a.matrix<T>(
"D");
1224 const std::vector<int> N = a.ints(
"N");
1225 const Matrix<T> V = a.matrix<T>(
"V");
1226 const std::vector<int> nservers = a.ints(
"nservers");
1227 if (!a.has(
"sched")) (void)a.get(
"sched");
1228 const std::vector<pfqn::SchedStrategy> sched = lin_sched(a,
"sched");
1229 const bool lf = long_form(a,
"pfqn_ab_amva", {
"fcfsSchmidt",
"marginalProbMethod"},
1230 {
"fcfsSchmidt",
"marginalProbMethod"});
1231 const bool schmidt = a.boolean(
"fcfsSchmidt",
false);
1234 std::string m = a.text(
"marginalProbMethod",
"");
1235 for (
char& ch : m) ch =
static_cast<char>(std::tolower(
static_cast<unsigned char>(ch)));
1238 else if (m ==
"scat")
1241 throw InputError(
"pfqn_ab_amva: unknown marginalProbMethod '" + m +
1242 "'; expected \"ab\" or \"scat\"");
1245 const pfqn::AbAmvaResult<T> r =
1261 static Json run(Args& a) {
1262 const int M = int_arg(a,
"M");
1263 const int order = int_arg(a,
"order");
1264 const bool hasZ = a.has(
"Z");
1265 const Matrix<double> Z = a.matrix_or_empty<
double>(
"Z");
1268 for (std::size_t i = 0; i < Z.size(); ++i) Zsum += Z[i];
1277 static Json run(Args& a) {
1278 const std::vector<T> L = a.vector<T>(
"L");
1279 const T N = a.number<T>(
"N");
1282 Json out = g_lg(r.G, r.lG);
1290 static Json run(Args& a) {
1291 const std::vector<T> L = a.vector<T>(
"L");
1292 const int N = int_arg(a,
"N");
1293 const std::size_t d = depth(a,
"pfqn_hst", {{
"Z",
false}, {
"ist",
false}});
1294 const T Z = a.has(
"Z") ? a.number<T>(
"Z") : num_traits<T>::from_int(0);
1295 const std::size_t ist = a.has(
"ist") ? a.count(
"ist") : 0;
1297 pfqn::HstResult<T> r;
1322 std::string m = a.text(
"inner",
"");
1323 for (
char& c : m) c =
static_cast<char>(std::tolower(
static_cast<unsigned char>(c)));
1326 throw InputError(
"pfqn_clust: unknown inner method '" + m +
"'; expected \"lin\" or \"bs\"");
1331 static Json run(Args& a) {
1332 const Matrix<T> L = a.matrix<T>(
"L");
1333 const std::vector<T> N = a.vector<T>(
"N");
1334 const bool hasZ = a.has(
"Z");
1335 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
1336 const std::size_t d = depth(a,
"pfqn_clust",
1337 {{
"subnets",
true}, {
"localclasses",
true}, {
"inner",
false},
1338 {
"tol",
false}, {
"maxiter",
false}});
1339 std::vector<std::vector<std::size_t> > subnets, localclasses;
1340 if (
const Json* j = a.opt(
"subnets")) subnets = index_lists(*j,
"'subnets'",
false);
1341 if (
const Json* j = a.opt(
"localclasses"))
1342 localclasses = index_lists(*j,
"'localclasses'",
false);
1344 const double tol = a.has(
"tol") ? a.number<
double>(
"tol") : 0.0;
1345 const std::size_t maxiter = a.has(
"maxiter") ? a.count(
"maxiter") : 0;
1347 pfqn::AmvaResult<T> r;
1358 return amva_results(r,
"it");
1364 static Json run(Args& a) {
1365 const Matrix<T> L = a.matrix<T>(
"L");
1366 const std::vector<int> N = a.ints(
"N");
1367 const bool hasZ = a.has(
"Z");
1368 const Matrix<T> Z = a.matrix_or_empty<T>(
"Z");
1369 const Json* oj = a.opt(
"options");
1371 pfqn::NcResult<T> r;
1375 Args o(*oj,
"pfqn_gerasimov options");
1376 const std::size_t d =
1377 depth(o,
"pfqn_gerasimov options", {{
"tol",
false}, {
"maxterms",
false}});
1378 const double tol = o.has(
"tol") ? o.number<
double>(
"tol") : 0.0;
1379 const std::size_t maxterms = o.has(
"maxterms") ? o.count(
"maxterms") : 0;
1388 return g_lg(r.G, r.lG);
1394 static Json run(Args& a) {
1395 const Matrix<T> L = a.matrix<T>(
"L");
1396 const std::vector<T> N = a.vector<T>(
"N");
1397 const std::size_t d =
1398 depth(a,
"pfqn_looping", {{
"Z",
true}, {
"tol",
false}, {
"maxiter",
false}});
1399 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
1400 const double tol = a.has(
"tol") ? a.number<
double>(
"tol") : 0.0;
1401 const std::size_t maxiter = a.has(
"maxiter") ? a.count(
"maxiter") : 0;
1403 pfqn::LoopingBounds<T> r;
1418 out[
"converged"] = r.converged;
1423std::vector<std::size_t> busy_orders(
Args& a) {
1424 const std::vector<int> v = a.ints(
"n");
1425 std::vector<std::size_t> out;
1427 if (x < 0)
throw InputError(
"'n': a busy period order cannot be negative");
1428 out.push_back(
static_cast<std::size_t
>(x));
1434 static Json run(Args& a) {
1435 const std::vector<double> alpha = a.vector<
double>(
"alpha");
1436 const Matrix<double> mu = a.matrix<
double>(
"mu");
1437 const Matrix<double>
P = a.matrix<
double>(
"P");
1438 const double N = a.number<
double>(
"N");
1439 const std::vector<std::size_t> subnet = indices(a,
"subnet");
1440 const std::vector<std::size_t> n = busy_orders(a);
1441 const std::size_t d = depth(a,
"pfqn_busyp", {{
"gamma",
true}, {
"tol",
false}});
1442 const std::vector<double> gamma = a.vector_or_empty<
double>(
"gamma");
1443 const double tol = a.has(
"tol") ? a.number<
double>(
"tol") : 0.0;
1445 pfqn::BusyPeriodResult r;
1461 static Json run(Args& a) {
1462 const Matrix<double> alpha = a.matrix<
double>(
"alpha");
1463 const Matrix<double> mu = a.matrix<
double>(
"mu");
1464 const std::vector<Matrix<double> >
P = a.matrices<
double>(
"P");
1465 const std::vector<double> N = a.vector<
double>(
"N");
1466 const std::vector<std::size_t> subnet = indices(a,
"subnet");
1467 const std::vector<std::size_t> n = busy_orders(a);
1468 const std::size_t d = depth(a,
"pfqn_busyp_clw",
1469 {{
"gamma",
true}, {
"isdelay",
true}, {
"method",
false}});
1470 const Matrix<double> gamma = a.matrix_or_empty<
double>(
"gamma");
1471 std::vector<bool> isdelay;
1472 if (
const Json* j = a.opt(
"isdelay")) isdelay = bool_vector(*j,
"'isdelay'");
1473 const std::string method = a.text(
"method",
"");
1489struct OpBusypMulticlass {
1490 static Json run(Args& a) {
1491 const Matrix<double> alpha = a.matrix<
double>(
"alpha");
1492 const Matrix<double> mu = a.matrix<
double>(
"mu");
1493 const std::vector<Matrix<double> >
P = a.matrices<
double>(
"P");
1494 const std::vector<double> N = a.vector<
double>(
"N");
1495 const std::vector<std::size_t> subnet = indices(a,
"subnet");
1496 const std::vector<std::size_t> n = busy_orders(a);
1497 const std::size_t d =
1498 depth(a,
"pfqn_busyp_multiclass",
1499 {{
"gamma",
true}, {
"phi",
true}, {
"tol",
false}, {
"jobclass",
false}});
1500 const Matrix<double> gamma = a.matrix_or_empty<
double>(
"gamma");
1501 const Matrix<double> phi = a.matrix_or_empty<
double>(
"phi");
1502 const double tol = a.has(
"tol") ? a.number<
double>(
"tol") : 0.0;
1503 const int jobclass = a.has(
"jobclass") ? int_arg(a,
"jobclass") : 0;
1505 std::vector<double> b;
1524 static Json run(Args& a) {
1525 const Matrix<T> L = a.matrix<T>(
"L");
1526 const std::vector<T> N = a.vector<T>(
"N");
1527 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
1530 Json out = g_lg(r.G, r.lG);
1533 out[
"A"] = encode_index_list(r.A);
1534 out[
"B"] = encode_index_list(r.B);
1541 static Json run(Args& a) {
1542 const Matrix<T> L = a.matrix<T>(
"L");
1543 const std::vector<int> N = a.ints(
"N");
1544 const std::vector<T> Z = a.vector<T>(
"Z");
1545 const bool hasM = a.has(
"m");
1546 std::vector<long> m;
1547 for (
int x : a.ints_or_empty(
"m")) m.push_back(
static_cast<long>(x));
1548 const Json* oj = a.opt(
"options");
1550 pfqn::ClwResult<T> r;
1553 pfqn::ClwOptions opt;
1554 Args o(*oj,
"pfqn_clw options");
1555 if (o.has(
"l")) opt.l = o.ints(
"l");
1556 if (o.has(
"gamma")) opt.gamma = o.vector<
double>(
"gamma");
1557 if (o.has(
"euler")) opt.euler = o.boolean(
"euler", opt.euler);
1558 if (o.has(
"euler_n")) opt.eulerN = int_arg(o,
"euler_n");
1559 if (o.has(
"euler_m")) opt.eulerM = int_arg(o,
"euler_m");
1560 if (o.has(
"euler_tol")) opt.eulerTol = o.number<
double>(
"euler_tol");
1561 if (o.has(
"euler_maxm")) opt.eulerMaxM = int_arg(o,
"euler_maxm");
1562 if (o.has(
"dimred")) opt.dimred = o.boolean(
"dimred", opt.dimred);
1563 if (o.has(
"dimred_maxd")) opt.dimredMaxD = int_arg(o,
"dimred_maxd");
1564 if (o.has(
"beta")) opt.beta = o.vector<
double>(
"beta");
1570 return g_lg(r.G, r.lG);
1574struct OpHarelBounds {
1576 static Json run(Args& a) {
1577 const std::vector<T> rho = a.vector<T>(
"rho");
1578 const int N = int_arg(a,
"N");
1579 const bool lf = a.has(
"Z") || a.has(
"maxUB");
1580 const T Z = a.has(
"Z") ? a.number<T>(
"Z") : num_traits<T>::from_int(0);
1582 const int maxUB = a.has(
"maxUB") ? int_arg(a,
"maxUB") : 0;
1584 if (lf && !a.has(
"Z"))
1585 throw InputError(
"pfqn_harel_bounds: 'maxUB' is given but 'Z' is not; the C++ port "
1586 "takes 'Z' positionally before 'maxUB'. Give 'Z' as well.");
1587 const pfqn::HarelBoundsResult<T> r =
1591 const std::vector<T> UB(r.UB.begin() + 1, r.UB.end());
1592 const std::vector<T> TH(r.TH.begin() + 1, r.TH.end());
1614 static Json run(Args& a) {
1615 const std::vector<T> L = a.vector<T>(
"L");
1616 const int N = int_arg(a,
"N");
1618 if (
const Json* sj = a.opt(
"S")) {
1620 for (
double v : sd) {
1621 if (std::isinf(v) && v > 0) {
1623 }
else if (!(v >= 1) || v != std::floor(v)) {
1624 throw InputError(
"pfqn_cftp: S must hold positive integer server counts or "
1627 S.push_back(
static_cast<int>(v));
1631 const std::size_t nsamples = a.count(
"nsamples", 1);
1632 const std::string m = a.text(
"method",
"cftp");
1636 else throw InputError(
"pfqn_cftp: method must be 'cftp' or 'approx', got '" + m +
"'");
1639 const pfqn::CftpResult<T> r =
pfqn::pfqn_cftp(L, N, S, nsamples, method, rng);
1640 Matrix<double> X(r.X.rows(), r.X.cols());
1641 for (std::size_t i = 0; i < X.rows(); ++i)
1642 for (std::size_t j = 0; j < X.cols(); ++j) X(i, j) = r.X(i, j);
1643 std::vector<double> horizon(r.horizon.begin(), r.horizon.end());
1657 std::size_t samples = 10000;
1658 std::uint64_t seed = 0;
1661inline IsOptions read_is_options(
Args& a,
const std::string& fn) {
1662 const Json* oj = a.opt(
"options");
1664 throw InputError(fn +
": options.seed is required; the port draws from a seeded "
1665 "generator and has no session RNG to fall back on");
1666 Args op(*oj, fn +
" options");
1668 o.samples = op.count(
"samples", o.samples);
1677 static Json run(Args& a) {
1678 const Matrix<T> L = a.matrix<T>(
"L");
1679 const std::vector<int> N = a.ints(
"N");
1680 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
1681 const IsOptions o = read_is_options(a,
"pfqn_is");
1684 const pfqn::NcResult<T> r =
pfqn::pfqn_is(L, N, Z, o.samples, rng);
1685 return g_lg(r.G, r.lG);
1692 static Json run(Args& a) {
1693 const Matrix<T> L = a.matrix<T>(
"L");
1694 const std::vector<int> N = a.ints(
"N");
1695 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
1696 const Matrix<T> mu = a.matrix_or_empty<T>(
"mu");
1697 const IsOptions o = read_is_options(a,
"pfqn_ld_is");
1701 return g_lg(r.G, r.lG);
1708 static Json run(Args& a) {
1709 const Matrix<T> L = a.matrix<T>(
"L");
1710 const std::vector<T> N = a.vector<T>(
"N");
1711 const std::vector<T> Z = a.vector_or_empty<T>(
"Z");
1712 const std::size_t I = a.count(
"I", 100000);
1716 return g_lg(r.G, r.lG,
"Gn",
"lGn");
1788 const std::string callables =
1789 "its scaling argument is a vector of callables (one std::function per station), which "
1790 "has no JSON representation.";
1791 t[
"pfqn_cdfun"] =
"pfqn_cdfun: " + callables;
1792 t[
"pfqn_jdfun"] =
"pfqn_jdfun: " + callables;
1793 const std::string oirate =
1794 "its rate argument mu is a vector of OiRate callables (std::function of the occupancy "
1795 "vector), which has no JSON representation.";
1796 t[
"pfqn_clwjd"] =
"pfqn_clwjd: " + oirate;
1797 t[
"pfqn_clwoi"] =
"pfqn_clwoi: " + oirate;
Internal to the –api dispatcher: what a per-domain translation unit needs to add entries to the table...
#define LINE_PFQN_A_LNZ(Name, fn, gk, lk)
The (L, N[, Z]) shape of the asymptotic expansions, returning G and lG.
UnsupportedError(const std::string &what)
Named-argument reader over the parsed JSON object.
DacResult< T > pfqn_dac(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const Matrix< T > &mu)
Distribution Analysis by Chain (de Souza e Silva, UCLA CSD-870023, 1987): the JOINT queue-length dist...
NcResult< T > pfqn_ld_is(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const Matrix< T > &mu, std::size_t samples, McRng &rng)
Importance-sampling estimate of the normalizing constant of a closed LOAD-DEPENDENT product-form netw...
BusyPeriodResult pfqn_busyp(const std::vector< double > &alpha, const RateSource &mu, const Matrix< T > &P, double N, const std::vector< std::size_t > &subnet, const std::vector< std::size_t > &n, const std::vector< double > &gamma={}, double tol=PFQN_BUSYP_DEFAULT_TOL)
Mean busy period of order n for the subnetwork.
std::mt19937_64 McRng
The generator type every Monte Carlo entry point in this tree accepts.
AghqResult< T > pfqn_aghq(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, std::size_t q)
AmvaResult< T > pfqn_clust(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, const std::vector< std::vector< std::size_t > > &subnets, const std::vector< std::vector< std::size_t > > &localclasses, ClustInner inner=ClustInner::Linearizer, double tol=1e-6, std::size_t maxiter=1000)
de Souza e Silva-Lavenberg-Muntz Clustering Approximation (CA).
T pfqn_grnmol(const Matrix< T > &L, const std::vector< int > &N)
Normalizing constant by the closed-form Grundmann-Moeller rule.
NcResult< T > pfqn_gldsingle(const Matrix< T > &L, int N, const Matrix< T > &mu)
Exact normalizing constant of a SINGLE-CLASS closed network whose stations are load dependent.
LinearizerResult< T > pfqn_gflinearizer(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< SchedStrategy > &type, double tol, int maxiter, const T &alpha, const Matrix< T > &QN0)
Generalized fixed-point Linearizer with a single scaling exponent shared by every class (De Souza e S...
NcResult< T > pfqn_lldsingle(const Matrix< T > &L, int N, const Matrix< T > &mu)
Exact normalizing constant of a SINGLE-CLASS closed network whose stations are LIMITED load dependent...
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.
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.
LinearizerMxMethod
Which Linearizer variant solves the closed subnetwork.
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.
LinearizerResult< T > pfqn_conwayms(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &nservers, const std::vector< SchedStrategy > &type, double tol, int maxiter, const Matrix< T > &QN0)
Conway's multiserver Linearizer for chain-dependent FCFS queues (Conway 1989, "Fast Approximate Solut...
std::vector< double > pfqn_busyp_clw(const Matrix< T > &alpha, const Matrix< T > &mu, const std::vector< Matrix< T > > &P, const std::vector< double > &N, const std::vector< std::size_t > &subnet, const std::vector< std::size_t > &n, const Matrix< T > &gamma=Matrix< T >(), const std::vector< bool > &isdelay=std::vector< bool >(), const std::string &method="clw")
Mean busy period of order n for the subnetwork, via NC point evaluations.
LinearizerResult< T > pfqn_dmlin(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< SchedStrategy > &type, double tol, int maxiter, const Matrix< T > &QN0, int npasses=3)
de Souza e Silva-Muntz Improved Linearizer (IL).
LdmxEcResult< T > pfqn_ldmx_ec(const std::vector< T > &lambda, const Matrix< T > &D, const Matrix< T > &mu)
Bruell-Balbo-Afshari effective-capacity terms for a MIXED open/closed network with limited load depen...
ChowVariant
Legacy compatibility selector; JMT-compatible Chow ignores it.
std::vector< T > pfqn_lldfun(const std::vector< T > &n, const Matrix< T > &lldscaling, const std::vector< double > &nservers)
AMVA-QD limited-load-dependence function.
constexpr int cftp_inf_servers
Sentinel for an infinite-server (delay) station, the reference's S = Inf.
HarelBoundsResult< T > pfqn_harel_bounds(const std::vector< T > &rho, int N, const T &Z, int maxUB)
Both bounds, plus the exact throughputs the upper bounds extrapolate from.
HstResult< T > pfqn_hst(const std::vector< T > &L, int N, const T &Z, std::size_t ist)
Operational sensitivity of throughput to homogeneous-service-time (HST) violations,...
ExpandResult< T > pfqn_expand(const Matrix< T > &QN, const Matrix< T > &UN, const Matrix< T > &CN, const std::vector< std::size_t > &mapping)
Expand per-station metrics from a reduced model back to the original station set.
T pfqn_lcfsqn_nc(const std::vector< T > &alpha, const std::vector< T > &beta, const std::vector< int > &N)
Normalizing constant of the two-station multiclass LCFS network as a sum of PERMANENTS,...
AmvaResult< T > pfqn_chow(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, const std::vector< AmvaSched > &type, double tol=1e-6, std::size_t maxiter=1000, const Matrix< T > &QN0=Matrix< T >(), ChowVariant variant=ChowVariant::Forward)
JMT-compatible Chow approximate MVA.
LldResult< T > pfqn_lld(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &mu)
Normalizing constant of a multiclass LIMITED load-dependent closed model.
constexpr int kOpenClass
Population sentinel marking an open class, standing in for MATLAB's Inf.
T pfqn_jointmarg(const std::vector< int > &n, const Matrix< T > &L, const std::vector< int > &N, const std::vector< std::size_t > &infset, const T &G, const std::string &engine="exact", std::uint64_t seed=0)
Joint probability of the per-station TOTAL queue lengths.
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 ...
ClustInner
Which algorithm runs inside a subnetwork.
DncResult< T > pfqn_dnc(const std::vector< T > &L, const T &N)
Distinct-load Normalizing Constant (DNC) at a nonintegral population.
LinearizerResult< T > pfqn_linearizermx(const std::vector< T > &lambda, const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &nservers, const std::vector< SchedStrategy > &type, double tol, int maxiter, LinearizerMxMethod method, const Matrix< T > &QN0)
Linearizer for mixed open/closed queueing networks.
LdBcmpBound< T > pfqn_ldbcmp(const std::vector< T > &L, const T &N, const T &Z, const std::vector< T > &c, const T &tol)
Anselmi-Cremonesi (2008) lower throughput bound for a closed single-class BCMP network with load-depe...
AmvaResult< T > pfqn_bs(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, const std::vector< AmvaSched > &type, double tol=1e-6, std::size_t maxiter=1000, const Matrix< T > &QN0=Matrix< T >())
Bard-Schweitzer approximate MVA.
AbAmvaResult< T > pfqn_ab_amva(const Matrix< T > &S, const std::vector< int > &N, const Matrix< T > &v, const std::vector< int > &nservers, const std::vector< SchedStrategy > &sched, bool fcfsSchmidt, AbMarginalMethod method)
Akyildiz-Bolch approximate MVA for multi-server BCMP networks.
LoopingBounds< T > pfqn_looping(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, double tol=1e-6, std::size_t maxiter=1000)
Eager Looping bounds for closed multiclass product-form networks.
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.
AmvaResult< T > pfqn_lcp(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, const std::vector< AmvaSched > &type, double tol=1e-6, std::size_t maxiter=1000, const Matrix< T > &QN0=Matrix< T >())
Bard Large Customer Population (LCP) approximate MVA.
AmvaResult< T > pfqn_aql(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, double tol=1e-7, std::size_t maxiter=1000)
Aggregate Queue Length (AQL) approximate MVA.
FncResult< T > pfqn_fnc(const Matrix< T > &alpha)
Automatic offset search (the one-argument MATLAB branch).
LinearizerResult< T > pfqn_egflinearizer(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< SchedStrategy > &type, double tol, int maxiter, const std::vector< T > &alpha, const Matrix< T > &QN0, int npasses=3)
Extended generalized fixed-point Linearizer (De Souza e Silva and Muntz's generalization of Chandy an...
LinearizerResult< T > pfqn_linearizerms(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &nservers, const std::vector< SchedStrategy > &type, double tol, int maxiter, const Matrix< T > &QN0)
Multiserver Linearizer (Krzesinski's Linearizer as described in Conway 1989, with De Souza e Silva an...
LinearizerResult< T > pfqn_linearizer(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< SchedStrategy > &type, double tol, int maxiter, const Matrix< T > &QN0)
Chandy-Neuse Linearizer for single-server stations.
CbhBounds< T > pfqn_cbh(const std::vector< T > &L, int N, const T &Z, int level)
Convolutional Bound Hierarchy (Dowdy, Eager, Gordon and Saxton 1984) on the throughput of a single-cl...
T pfqn_lap(const std::vector< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Laplace approximation of the normalizing constant of a repairman (single-queue, multiclass) model.
std::vector< double > pfqn_busyp_multiclass(const Matrix< T > &alpha, const Matrix< T > &mu, const std::vector< Matrix< T > > &P, const std::vector< double > &N, const std::vector< std::size_t > &subnet, const std::vector< std::size_t > &n, const Matrix< T > &gamma=Matrix< T >(), const Matrix< T > &phi=Matrix< T >(), double tol=PFQN_BUSYP_DEFAULT_TOL, int jobclass=-1)
Mean busy period of order n for the subnetwork, multichain.
ComomRmResult< T > pfqn_comomrm_ld(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const Matrix< T > &mu)
CoMoM for the repairman model with an arbitrary LOAD-DEPENDENT rate lattice at the single queueing st...
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...
DivdiffLdResult< T > pfqn_divdiff_ld(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const Matrix< T > &mu)
Exact load-dependent normalizing constant by divided differences of a single-class constant.
CftpMethod
Which sampler to run.
@ Cftp
exact, monotone coupling from the past
@ Approx
the rapidly-mixing approximate sampler M_A
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.
LcfsQnResult< T > pfqn_lcfsqn_ca(const std::vector< T > &alpha, const std::vector< T > &beta, const std::vector< int > &N)
Convolution algorithm for the two-station multiclass LCFS queueing network of Casale,...
CftpResult< T > pfqn_cftp(const std::vector< T > &L, int N, const std::vector< int > &S, std::size_t nsamples, CftpMethod method, McRng &rng)
Perfect stationary state sampling for closed single-class multiserver product-form networks,...
double pfqn_cntol(const std::vector< T > &N)
Termination cutoff at the given population vector.
CycletResult pfqn_cyclet_ofree(const std::vector< double > &v, const std::vector< double > &mu, std::size_t N, const std::vector< std::vector< std::size_t > > &paths, const std::vector< double > &tset, const std::string &method="auto", std::size_t nmom=3, const std::vector< double > &pathprob={}, const std::string <i_method="euler", double tol=1e-8)
Exact passage-time density, CDF and moments along the overtake-free paths paths, mixed by pathprob.
ExplicitResult< T > pfqn_explicit_ld(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &mu, 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 LIMITED LOAD-DEPENDENT network.
LcfsMvaResult< T > pfqn_lcfsqn_mva(const std::vector< T > &alpha, const std::vector< T > &beta, const std::vector< int > &N)
Exact mean value analysis of the two-station multiclass LCFS network of Casale, QUESTA 2026 (station ...
AbMarginalMethod
Which marginal-probability rule the multiserver correction uses.
@ Ab
the Akyildiz-Bolch weight function
@ Scat
two-point scatter around floor(Qtot)
std::uint64_t required_seed(Args &a, const std::string &fn, const char *spelled="seed")
The seed of a function whose port draws from a caller-owned generator.
std::vector< int > int_vector_from_json(const Json &j, const std::string &where)
An integer vector; a non-integral entry is an error, never a truncation.
void register_library_only_pfqn_a(LibraryOnlyTable &t)
T number_from_json(const Json &j, const std::string &where)
std::vector< T > vector_from_json(const Json &j, const std::string &where)
A flat numeric vector: 1-D array, or a 1-row / 1-column 2-D array.
Json encode_vector(const std::vector< T > &v)
Json encode_matrix(const Matrix< T > &m)
std::string shortest_decimal(double v)
The shortest decimal literal that round-trips to v.
Json encode_scalar(const T &v)
Json encode_count(std::size_t n)
A count.
std::map< std::string, std::string > LibraryOnlyTable
name -> why the function has no named-JSON-argument form.
Json encode_ints(const std::vector< int > &v)
std::map< std::string, Invoker > DispatchTable
void register_api_pfqn_a(DispatchTable &t)
Conservation laws of a layered queueing network, enumerated from its structure.
Akyildiz-Bolch approximate MVA for multi-server BCMP networks.
Adaptive Gauss-Hermite quadrature of the simplex factor of the McKenna-Mitra integral.
Aggregate Queue Length (AQL) approximate MVA.
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).
Bard-Schweitzer approximate MVA.
Mean busy period of order n for a subnetwork of a product-form network.
Busy period of a subnetwork from point evaluations of the normalizing constant.
Multichain generalization of pfqn_busyp.
Convolutional Bound Hierarchy (Dowdy, Eager, Gordon and Saxton 1984) on the throughput of a single-cl...
Perfect stationary state sampling for closed single-class multiserver product-form networks,...
JMT-compatible Chow approximate MVA.
de Souza e Silva-Lavenberg-Muntz Clustering Approximation (CA).
Choudhury-Leung-Whitt normalization constant by numerical inversion of the generating function (JACM ...
Chandy-Neuse population-scaled termination cutoff for approximate MVA.
CoMoM for the repairman model with an arbitrary LOAD-DEPENDENT rate lattice at the single queueing st...
Conway's multiserver Linearizer for chain-dependent FCFS queues (Conway 1989, "Fast Approximate Solut...
Normalizing constant by Grundmann-Moeller cubature over the simplex.
Integrand-evaluation count of pfqn_cub, and the budget pfqn_nc prices it against.
Exact passage-time law along an OVERTAKE-FREE PATH of a closed single-chain tree-like product-form ne...
Distribution Analysis by Chain (de Souza e Silva, UCLA CSD-870023, 1987): the JOINT queue-length dist...
Exact load-dependent normalizing constant by divided differences of a single-class constant.
de Souza e Silva-Muntz Improved Linearizer (IL).
Distinct-load Normalizing Constant (DNC) at a nonintegral population.
Extended generalized fixed-point Linearizer (De Souza e Silva and Muntz's generalization of Chandy an...
Expand per-station metrics from a reduced model back to the original station set.
Explicit closed-form normalizing constant of a multiclass closed network.
Explicit closed-form normalizing constant of a multiclass LIMITED LOAD-DEPENDENT network.
Load-dependent rates of the functional server f(n) = n + c.
Gerasimov's residue (closed-form) normalizing constant, generalized to R classes.
Generalized fixed-point Linearizer with a single scaling exponent shared by every class (De Souza e S...
Exact normalizing constant of a SINGLE-CLASS closed network whose stations are load dependent.
Normalizing constant by the closed-form Grundmann-Moeller rule.
Harel-Namn-Sturm throughput bounds for a single-class closed network.
Operational sensitivity of throughput to homogeneous-service-time (HST) violations,...
Importance-sampling estimate of the normalizing constant of a closed LOAD-INDEPENDENT product-form ne...
Joint queue-length probability of a closed product-form network.
Joint probability of the per-station TOTAL queue lengths.
Knessl-Tier asymptotic expansion of the normalizing constant.
Laplace approximation of the normalizing constant of a repairman (single-queue, multiclass) model.
Convolution algorithm for the two-station multiclass LCFS queueing network of Casale,...
Exact mean value analysis of the two-station multiclass LCFS network of Casale, QUESTA 2026 (station ...
Normalizing constant of the two-station multiclass LCFS network as a sum of PERMANENTS,...
Bard Large Customer Population (LCP) approximate MVA.
Importance-sampling estimate of the normalizing constant of a closed LOAD-DEPENDENT product-form netw...
Anselmi-Cremonesi (2008) lower throughput bound for a closed single-class BCMP network with load-depe...
Bruell-Balbo-Afshari effective-capacity terms for a MIXED open/closed network with limited load depen...
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.
Chandy-Neuse Linearizer for single-server stations.
Multiserver Linearizer (Krzesinski's Linearizer as described in Conway 1989, with De Souza e Silva an...
Linearizer for mixed open/closed queueing networks.
Normalizing constant of a multiclass LIMITED load-dependent closed model.
AMVA-QD limited-load-dependence function.
Exact normalizing constant of a SINGLE-CLASS closed network whose stations are LIMITED load dependent...
Eager Looping bounds for closed multiclass product-form networks.
Logistic-sampling estimate of the normalizing constant of a closed product-form network.