80std::size_t index_from_json(
const Json& j,
const std::string& where) {
83 const long long v = std::strtoll(text.c_str(), &end, 10);
84 if (end == text.c_str() || *end !=
'\0')
85 throw InputError(where +
": an index must be an integer, got " + text);
86 if (v < 0)
throw InputError(where +
": an index cannot be negative, got " + text);
87 return static_cast<std::size_t
>(v);
91std::vector<std::size_t> indices_from_json(
const Json& j,
const std::string& where) {
92 std::vector<std::size_t> out;
94 out.push_back(index_from_json(j, where));
97 for (std::size_t k = 0; k < j.size(); ++k)
98 out.push_back(index_from_json(j[k], where +
"[" + std::to_string(k) +
"]"));
102std::vector<std::size_t> read_indices(
Args& a,
const char* key) {
103 return indices_from_json(a.get(key), a.get(key).is_null() ? key : std::string(key));
107std::vector<std::vector<std::size_t> > read_index_lists(
Args& a,
const char* key) {
108 const Json& j = a.get(key);
109 const std::string where = std::string(key);
110 if (!j.is_array())
throw InputError(where +
": expected a list of index lists");
111 std::vector<std::vector<std::size_t> > out;
112 for (std::size_t b = 0; b < j.size(); ++b)
113 out.push_back(indices_from_json(j[b], where +
"[" + std::to_string(b) +
"]"));
117Json encode_indices(
const std::vector<std::size_t>& v) {
118 Json a = Json::array();
119 for (std::size_t i = 0; i < v.size(); ++i) a.push_back(
static_cast<std::uint64_t
>(v[i]));
124std::vector<bool> read_flags(
Args& a,
const char* key) {
125 const Json& j = a.get(key);
126 const std::string where = std::string(key);
127 std::vector<bool> out;
128 const Json flat = j.is_array() ? j : Json::array({j});
129 for (std::size_t k = 0; k < flat.size(); ++k) {
130 const Json& e = flat[k];
131 if (e.is_boolean()) {
132 out.push_back(e.get<
bool>());
135 if (text !=
"0" && text !=
"1")
136 throw InputError(where +
": a flag must be true, false, 0 or 1, got " + text);
137 out.push_back(text ==
"1");
145std::vector<std::vector<T> > read_vector_list(
Args& a,
const char* key) {
146 const Json& j = a.get(key);
147 const std::string where = std::string(key);
148 if (!j.is_array())
throw InputError(where +
": expected a list of vectors");
149 std::vector<std::vector<T> > out;
150 for (std::size_t i = 0; i < j.size(); ++i)
157std::vector<std::vector<T> > rows_of(
const Matrix<T>& m) {
158 std::vector<std::vector<T> > out(m.rows(), std::vector<T>(m.cols()));
159 for (std::size_t i = 0; i < m.rows(); ++i)
160 for (std::size_t k = 0; k < m.cols(); ++k) out[i][k] = m(i, k);
166mam::Mmap<T> mmap_from_json(
const Json& j,
const std::string& where) {
167 if (!j.is_array())
throw InputError(where +
": expected an MMAP, a list of matrices");
169 if (j.empty())
return m;
171 throw InputError(where +
": an MMAP is {D0, D1, D1^(1), ...}, got one matrix");
174 for (std::size_t k = 2; k < j.size(); ++k)
180std::vector<mam::Mmap<T> > read_mmap_list(
Args& a,
const char* key) {
181 const Json& j = a.get(key);
182 const std::string where = std::string(key);
183 if (!j.is_array())
throw InputError(where +
": expected a list of MMAPs");
184 std::vector<mam::Mmap<T> > out;
185 for (std::size_t i = 0; i < j.size(); ++i)
186 out.push_back(mmap_from_json<T>(j[i], where +
"[" + std::to_string(i) +
"]"));
191Json encode_mmap(
const mam::Mmap<T>& m) {
192 std::vector<Matrix<T> > cell;
193 cell.push_back(m.D0);
194 cell.push_back(m.D1);
195 for (
const Matrix<T>& d : m.Dc) cell.push_back(d);
200std::vector<std::complex<double> > read_complex(
Args& a,
const char* key) {
201 const Json& j = a.get(key);
202 const std::string where = std::string(key);
203 const Json flat = j.is_array() ? j : Json::array({j});
204 std::vector<std::complex<double> > out;
205 for (std::size_t k = 0; k < flat.size(); ++k) {
206 const Json& e = flat[k];
207 const std::string w = where +
"[" + std::to_string(k) +
"]";
209 if (e.size() != 2)
throw InputError(w +
": a complex number is a pair [re, im]");
218Json encode_complex(
const std::vector<std::complex<double> >& v) {
219 Json a = Json::array();
220 for (
const std::complex<double>& z : v) a.push_back(Json::array({
z.real(),
z.imag()}));
225const Json* sub_object(
Args& a,
const char* key) {
226 const Json* j = a.opt(key);
227 if (j && !j->is_object())
228 throw InputError(std::string(key) +
": expected an object with named fields");
233struct PassageOptions {
234 bool hasMethod =
false;
245PassageOptions read_passage_options(
Args& a,
const std::string& fn) {
247 const Json* j = sub_object(a,
"options");
249 Args op(*j, fn +
": options");
250 o.hasMethod = op.has(
"method");
251 if (o.hasMethod) o.method = op.text(
"method",
"");
252 o.hasLti = op.has(
"lti_method");
253 if (o.hasLti) o.lti = op.text(
"lti_method",
"");
255 if (o.hasLti && !(o.hasMethod && o.method ==
"lt"))
256 throw InputError(fn +
": options.lti_method selects the inversion of method 'lt' and "
257 "has no effect otherwise; set options.method to 'lt' or drop it");
266struct OpCtmcStochcomp {
268 static Json run(Args& a) {
269 const Matrix<T> Q = a.matrix<T>(
"Q");
270 const bool hasI = a.has(
"I");
271 const std::vector<std::size_t> I = hasI ? read_indices(a,
"I") : std::vector<std::size_t>();
291template <
class R,
class F>
292R call_tol_maxiter(
Args& a,
const std::string& fn, F f) {
293 const bool hasTol = a.has(
"tol"), hasMax = a.has(
"maxiter");
294 if (hasMax && !hasTol)
295 throw InputError(fn +
": 'maxiter' follows 'tol' in the MATLAB signature; name both");
296 const double tol = hasTol ? a.number<
double>(
"tol") : 0.0;
297 const long maxiter = hasMax ?
static_cast<long>(a.required_integer(
"maxiter")) : 0;
299 if (hasMax)
return f(3, tol, maxiter);
300 if (hasTol)
return f(2, tol, maxiter);
301 return f(1, tol, maxiter);
305struct OpCtmcUniformization {
307 static Json run(Args& a) {
308 const std::vector<T> pi0 = a.vector<T>(
"pi0");
309 const Matrix<T> Q = a.matrix<T>(
"Q");
310 const T t = a.number<T>(
"t");
311 const mc::UniformizationResult<T> r = call_tol_maxiter<mc::UniformizationResult<T> >(
312 a,
"ctmc_uniformization", [&](
int n,
double tol,
long maxiter) {
325struct OpCtmcTimeaverage {
327 static Json run(Args& a) {
328 const std::vector<T> pi0 = a.vector<T>(
"pi0");
329 const Matrix<T> Q = a.matrix<T>(
"Q");
330 const T t = a.number<T>(
"t");
331 const mc::TimeAverageResult<T> r = call_tol_maxiter<mc::TimeAverageResult<T> >(
332 a,
"ctmc_timeaverage", [&](
int n,
double tol,
long maxiter) {
351template <mc::detail::SweepKind K>
352struct OpCtmcClassical {
354 static Json run(Args& a) {
355 const Matrix<T> Q = a.matrix<T>(
"Q");
358 const double omega = (K == mc::detail::SweepKind::Sor) ? a.scalar<
double>(
"omega", 0.0)
359 : (K == mc::detail::SweepKind::GaussSeidel) ? 1.0 : 0.0;
360 const std::vector<T> p0 = a.vector_or_empty<T>(
"p0");
362 const mc::ClassicalResult<T> r = mc::detail::stationary_sweep_iterate(K, Q, tol, maxiter, omega, p0);
365 out[
"flag"] = r.flag;
367 out[
"iter"] =
static_cast<std::int64_t
>(r.iter);
368 if (K == mc::detail::SweepKind::Sor) out[
"omega"] =
encode_scalar(r.omega);
381 static Json run(Args& a) {
382 const Matrix<T> Q = a.matrix<T>(Dtmc ?
"P" :
"Q");
389 Json nan = Json::array();
390 for (std::size_t i = 0; i < Q.rows(); ++i) nan.push_back(
"NaN");
393 out[
"flag"] = r.flag;
402 static Json run(Args& a) {
403 const Matrix<T> Q = a.matrix<T>(Dtmc ?
"P" :
"Q");
413 static Json run(Args& a) {
414 const Matrix<double> C = a.matrix<
double>(
"C");
415 const Matrix<double> R = a.matrix<
double>(
"R");
424struct OpCtmcAccumulated {
426 static Json run(Args& a) {
427 const std::vector<T> pi0 = a.vector<T>(
"pi0");
428 const Matrix<T> Q = a.matrix<T>(
"Q");
429 const std::vector<T> t = a.vector<T>(
"t");
430 const mc::AccumulatedResult<T> r = call_tol_maxiter<mc::AccumulatedResult<T> >(
431 a,
"ctmc_accumulated", [&](
int n,
double tol,
long maxiter) {
449struct OpCtmcMemoryGate {
451 static Json run(Args& a) {
452 const double logN = a.number<
double>(
"logNstates");
453 a.unsupported(
"verbose",
454 "ctmc_memory_gate: 'verbose' prints to stdout, which carries the JSON "
455 "reply; the decision and its message are returned as ok and msg");
456 const bool hasForce = a.has(
"force"), hasSafety = a.has(
"safetyFraction");
457 const bool force = hasForce ? a.boolean(
"force",
false) :
false;
458 const double safety = hasSafety ? a.number<
double>(
"safetyFraction") : 0.0;
460 mc::CtmcGateResult r;
469 out[
"msg"] = r.message;
475struct OpCtmcIsfeasible {
477 static Json run(Args& a) {
478 const Matrix<T> Q = a.matrix<T>(
"Q");
479 const bool hasTol = a.has(
"tol");
480 const T tol = hasTol ? a.number<T>(
"tol") : T();
489struct OpCtmcHittingTime {
491 static Json run(Args& a) {
492 const Matrix<T> Q = a.matrix<T>(
"Q");
493 const std::vector<std::size_t> target = read_indices(a,
"targetStates");
501struct OpDtmcHittingTime {
503 static Json run(Args& a) {
504 const Matrix<T>
P = a.matrix<T>(
"P");
505 const std::vector<std::size_t> target = read_indices(a,
"targetStates");
518struct OpDtmcTransient {
520 static Json run(Args& a) {
521 const Matrix<T>
P = a.matrix<T>(
"P");
522 const bool hasPi0 = a.has(
"pi0"), hasSteps = a.has(
"steps");
523 const std::vector<T> pi0 = a.vector_or_empty<T>(
"pi0");
524 const std::size_t steps = hasSteps ? a.count(
"steps") : 1;
534struct OpCtmcPassagePh {
536 static Json run(Args& a) {
537 const Matrix<T> Q = a.matrix<T>(
"Q");
538 const std::vector<T> pi0 = a.vector_or_empty<T>(
"pi0");
539 const std::vector<std::size_t> target = read_indices(a,
"target");
546 out[
"keep"] = encode_indices(r.keep);
553struct OpCtmcPassageLst {
555 static Json run(Args& a) {
556 const Matrix<T> Q = a.matrix<T>(
"Q");
557 const std::vector<T> pi0 = a.vector_or_empty<T>(
"pi0");
558 const std::vector<std::size_t> target = read_indices(a,
"target");
559 const std::vector<std::complex<double> > s = read_complex(a,
"s");
568struct OpCtmcPassageMoments {
570 static Json run(Args& a) {
571 const Matrix<T> Q = a.matrix<T>(
"Q");
572 const std::vector<T> pi0 = a.vector_or_empty<T>(
"pi0");
573 const std::vector<std::size_t> target = read_indices(a,
"target");
574 const bool hasN = a.has(
"nmax");
575 const std::size_t nmax = hasN ? a.count(
"nmax") : 0;
591struct OpCtmcPassageTime {
593 static Json run(Args& a) {
594 const Matrix<T> Q = a.matrix<T>(
"Q");
595 const std::vector<T> pi0 = a.vector_or_empty<T>(
"pi0");
596 const std::vector<std::size_t> target = read_indices(a,
"target");
597 const std::vector<double> tset = a.vector<
double>(
"tset");
598 const PassageOptions o = read_passage_options(a,
"ctmc_passage_time");
600 const mc::PassageCurve<T> c =
613 o2[
"keep"] = encode_indices(ph.keep);
620struct OpCtmcPassageTaboo {
622 static Json run(Args& a) {
623 const Matrix<T> Q = a.matrix<T>(
"Q");
624 const std::vector<T> pi0 = a.vector_or_empty<T>(
"pi0");
625 const std::vector<std::size_t> target = read_indices(a,
"target");
626 const std::vector<std::size_t> taboo = read_indices(a,
"taboo");
627 const bool hasT = a.has(
"tset");
628 const std::vector<double> tset = a.vector_or_empty<
double>(
"tset");
629 const PassageOptions o = read_passage_options(a,
"ctmc_passage_taboo");
631 const mc::PassageTaboo<T> r =
649 o2[
"keep"] = encode_indices(r.keep);
650 o2[
"target"] = encode_indices(r.target);
651 o2[
"taboo"] = encode_indices(r.taboo);
652 o2[
"method"] = r.method;
659struct OpCtmcPassageTabooMoments {
661 static Json run(Args& a) {
662 const Matrix<T> Q = a.matrix<T>(
"Q");
663 const std::vector<T> pi0 = a.vector_or_empty<T>(
"pi0");
664 const std::vector<std::size_t> target = read_indices(a,
"target");
665 const std::vector<std::size_t> taboo = read_indices(a,
"taboo");
666 const bool hasN = a.has(
"nmax");
667 const std::size_t nmax = hasN ? a.count(
"nmax") : 0;
669 const mc::PassageTabooMoments<T> r =
687 static Json run(Args& a) {
688 const std::vector<T> p = a.vector<T>(
"p");
689 const std::size_t N = a.count(
"N");
703 static Json run(Args& a) {
704 const Matrix<T>
P = a.matrix<T>(
"P");
705 const std::size_t N = a.count(
"N");
727struct OpNpfqnTrafficIdc {
729 static Json run(Args& a) {
730 const std::vector<T> lambda0 = a.vector<T>(
"lambda0");
731 const Matrix<T>
P = a.matrix<T>(
"P");
732 const std::vector<T> c2a0 = a.vector<T>(
"c2a0");
733 const std::vector<T> mu = a.vector<T>(
"mu");
734 const std::vector<T> cs2 = a.vector<T>(
"cs2");
735 a.unsupported(
"a0IdcFun",
"npfqn_traffic_idc: a0IdcFun is a function handle with no "
736 "JSON form; it is used only by npfqn_traffic_idc_at");
737 a.unsupported(
"sIdcFun",
"npfqn_traffic_idc: sIdcFun is a function handle with no "
738 "JSON form; it is used only by npfqn_traffic_idc_at");
739 const Json* cj = sub_object(a,
"corrections");
740 npfqn::TrafficIdcCorrections corr;
742 Args c(*cj,
"npfqn_traffic_idc: corrections");
743 if (c.has(
"alpha")) corr.alpha = c.boolean(
"alpha", corr.alpha);
744 if (c.has(
"beta")) corr.beta = c.boolean(
"beta", corr.beta);
777struct OpNpfqnTrafficSplitCs {
779 static Json run(Args& a) {
780 const std::vector<Matrix<T> > M = a.matrices<T>(
"MMAP");
781 const Matrix<T>
P = a.matrix<T>(
"P");
782 a.unsupported(
"config",
"npfqn_traffic_split_cs: the reference accepts config but never "
783 "reads it; there is nothing for it to select");
786 Json out = Json::array();
794npfqn::Merge merge_from_text(
const std::string& s,
const std::string& fn) {
799 throw InputError(fn +
": config.merge must be 'default', 'super', 'mixture' or 'interpos', got '" +
803npfqn::Compress compress_from_text(
const std::string& s,
const std::string& fn) {
806 throw InputError(fn +
": config.compress must be 'default' or 'none', got '" + s +
"'");
810struct OpNpfqnTrafficMergeCs {
812 static Json run(Args& a) {
813 const std::vector<mam::Mmap<T> > flows = read_mmap_list<T>(a,
"MMAP");
814 const Matrix<T> prob = a.matrix<T>(
"prob");
815 const Json* cj = sub_object(a,
"config");
816 bool hasMerge =
false;
819 Args c(*cj,
"npfqn_traffic_merge_cs: config");
820 hasMerge = c.has(
"merge");
821 if (hasMerge) merge = merge_from_text(c.text(
"merge",
""),
"npfqn_traffic_merge_cs");
828 out[
"SMMAP"] = encode_mmap(s);
834struct OpNpfqnTrafficMerge {
836 static Json run(Args& a) {
837 const std::vector<mam::Mmap<T> > flows = read_mmap_list<T>(a,
"MMAP");
838 const Json* cj = sub_object(a,
"config");
839 npfqn::MergeConfig cfg;
841 Args c(*cj,
"npfqn_traffic_merge: config");
842 if (c.has(
"merge")) cfg.merge = merge_from_text(c.text(
"merge",
""),
"npfqn_traffic_merge");
843 if (c.has(
"compress"))
844 cfg.compress = compress_from_text(c.text(
"compress",
""),
"npfqn_traffic_merge");
850 out[
"SMMAP"] = encode_mmap(s);
856struct OpNpfqnRqnaWeight {
858 static Json run(Args& a) {
859 const bool vec = a.get(
"t").is_array();
862 const std::vector<T> t = a.vector<T>(
"t");
866 const T t = a.number<T>(
"t");
875struct OpNpfqnTrafficRqt {
877 static Json run(Args& a) {
878 const std::vector<T> lambda0 = a.vector<T>(
"lambda0");
879 const std::vector<T> Gamma0 = a.vector<T>(
"Gamma0");
880 const std::vector<T> alpha0 = a.vector<T>(
"alpha0");
881 const Matrix<T> F = a.matrix<T>(
"F");
896struct OpNpfqnBndBpt {
898 static Json run(Args& a) {
899 const std::vector<T> lambda0 = a.vector<T>(
"lambda0");
900 const std::vector<T> mu = a.vector<T>(
"mu");
901 const Matrix<T>
P = a.matrix<T>(
"P");
902 const std::vector<std::size_t> stationOf = read_indices(a,
"stationOf");
903 const std::vector<T> c = a.vector_or_empty<T>(
"c");
927struct OpNpfqnBndBgt {
929 static Json run(Args& a) {
930 const std::vector<T> lambda = a.vector<T>(
"lambda");
931 const std::vector<std::vector<T> > mu = read_vector_list<T>(a,
"mu");
932 const std::vector<std::vector<std::size_t> > sigma = read_index_lists(a,
"sigma");
937 for (
const std::vector<std::size_t>& s : sigma)
938 for (std::size_t j : s) J = std::max(J, j + 1);
945 Json fin = Json::array();
946 for (
bool b : r.finite) fin.push_back(b);
947 info[
"finite"] = fin;
959 info[
"classType"] = encode_indices(r.classType);
960 info[
"classStage"] = encode_indices(r.classStage);
961 info[
"classStation"] = encode_indices(r.classStation);
973struct OpNpfqnNonexpApprox {
975 static Json run(Args& a) {
976 a.unsupported(
"sn",
"npfqn_nonexp_approx: pass the two sn fields the routine reads, "
977 "isFCFS (sn.sched == FCFS per station) and rates (sn.rates)");
978 const std::string method = a.text(
"method",
"");
979 if (method.empty())
throw InputError(
"npfqn_nonexp_approx: missing required argument 'method'");
980 const std::vector<bool> isFCFS = read_flags(a,
"isFCFS");
981 const Matrix<T> rates = a.matrix<T>(
"rates");
982 const Matrix<T> ST = a.matrix<T>(
"ST");
983 const Matrix<T> V = a.matrix<T>(
"V");
984 const Matrix<T> SCV = a.matrix<T>(
"SCV");
985 const Matrix<T>
Tput = a.matrix<T>(
"T");
986 const Matrix<T> U = a.matrix<T>(
"U");
987 const std::vector<T> gamma = a.vector<T>(
"gamma");
988 const std::vector<T> nservers = a.vector<T>(
"nservers");
990 const npfqn::NonexpApproxResult<T> r =
1012 static Json run(Args& a) {
1013 a.unsupported(
"sn",
"npfqn_sqd: pass the arrays the routine unpacks from sn: ST, V, cap, "
1014 "isDelay, rt, stationToStateful and nclasses (see npfqn_sqd.h)");
1015 const std::vector<T> ST = a.vector<T>(
"ST");
1016 const std::vector<T> V = a.vector<T>(
"V");
1017 const std::vector<T> cap = a.vector<T>(
"cap");
1018 const std::vector<bool> isDelay = read_flags(a,
"isDelay");
1019 const Matrix<T> rt = a.matrix<T>(
"rt");
1020 const std::vector<std::size_t> s2s = read_indices(a,
"stationToStateful");
1021 const std::size_t nclasses = a.count(
"nclasses");
1022 const int N = a.required_integer(
"N");
1023 npfqn::SqdOptions<T> opt;
1025 if (a.has(
"calibrationMode")) {
1026 opt.calibrationMode = a.required_integer(
"calibrationMode");
1029 if (a.has(
"serverBlockingTime")) {
1030 opt.serverBlockingTime = a.boolean(
"serverBlockingTime", opt.serverBlockingTime);
1033 if (a.has(
"neighborMode")) {
1034 const std::string m = a.text(
"neighborMode",
"");
1035 if (m !=
"downstream" && m !=
"ownserver")
1036 throw InputError(
"npfqn_sqd: neighborMode must be 'downstream' or 'ownserver', got '" + m +
"'");
1037 opt.ownServerNeighbor = (m ==
"ownserver");
1040 if (a.has(
"v1Policy")) {
1041 const std::string m = a.text(
"v1Policy",
"");
1042 if (m !=
"compound" && m !=
"fresh")
1043 throw InputError(
"npfqn_sqd: v1Policy must be 'compound' or 'fresh', got '" + m +
"'");
1044 opt.freshV1 = (m ==
"fresh");
1047 if (a.has(
"initialV1")) {
1048 opt.initialV1 = a.vector_or_empty<T>(
"initialV1");
1052 const npfqn::SqdResult<T> r =
1054 : npfqn::
npfqn_sqd(ST, V, cap, isDelay, rt, s2s, nclasses, N);
1065struct OpNpfqnDpsMorrison {
1067 static Json run(Args& a) {
1068 const std::vector<T> N = a.vector<T>(
"N");
1069 const std::vector<T> Z = a.vector<T>(
"Z");
1070 const std::vector<T> S = a.vector<T>(
"S");
1071 const std::vector<T> w = a.vector<T>(
"w");
1081#define LINE_MC_AUX(f) aux[#f] = encode_scalar(r.f);
1100struct OpNpfqnFeedbackElim {
1102 static Json run(Args& a) {
1103 const Matrix<T>
P = a.matrix<T>(
"P");
1104 const std::vector<T> rho = a.vector<T>(
"rho");
1105 const std::vector<T> cs2 = a.vector_or_empty<T>(
"cs2");
1106 const std::vector<T> lambda = a.vector_or_empty<T>(
"lambda");
1107 const bool hasImm = a.has(
"immediateOnly");
1108 const bool imm = hasImm ? a.boolean(
"immediateOnly",
false) :
false;
1115 if (!r.modifiedScv.empty()) res[
"modifiedScv"] =
encode_vector(r.modifiedScv);
1116 if (!r.modifiedRates.empty()) res[
"modifiedRates"] =
encode_vector(r.modifiedRates);
1118 res[
"reductionExact"] = r.reductionExact;
1120 out[
"result"] = res;
1129Json env_json(
const snc::Env& e) {
1131 out[
"sigma"] = e.sigma;
1137snc::Env read_env(
Args& a,
const char* s,
const char* r) {
1139 e.sigma = a.number<
double>(s);
1140 e.rho = a.number<
double>(r);
1144struct OpSncEnvPoisson {
1145 static Json run(Args& a) {
1146 const double lambda = a.number<
double>(
"lambda"), theta = a.number<
double>(
"theta");
1152struct OpSncEnvCpoisson {
1153 static Json run(Args& a) {
1154 const double lambda = a.number<
double>(
"lambda"), mu = a.number<
double>(
"mu");
1155 const double theta = a.number<
double>(
"theta");
1162struct OpSncEnvTokenbucket {
1163 static Json run(Args& a) {
1164 const double b = a.number<
double>(
"b"), r = a.number<
double>(
"r");
1165 const bool hasTheta = a.has(
"theta");
1166 const double theta = hasTheta ? a.number<
double>(
"theta") : 0.0;
1173 static Json run(Args& a) {
1174 const Matrix<double> D0 = a.matrix<
double>(
"D0"), D1 = a.matrix<
double>(
"D1");
1175 const double theta = a.number<
double>(
"theta");
1182struct OpSncSrvRate {
1183 static Json run(Args& a) {
1184 const double C = a.number<
double>(
"C");
1185 const bool hasTheta = a.has(
"theta");
1186 const double theta = hasTheta ? a.number<
double>(
"theta") : 0.0;
1193 static Json run(Args& a) {
1194 const double mu = a.number<
double>(
"mu"), theta = a.number<
double>(
"theta");
1200struct OpSncLeftover {
1201 static Json run(Args& a) {
1202 const snc::Env srv = read_env(a,
"sigmaS",
"rhoS");
1203 const snc::Env cross = read_env(a,
"sigmaX",
"rhoX");
1211 static Json run(Args& a) {
1212 const snc::Env s1 = read_env(a,
"sigma1",
"rho1");
1213 const snc::Env s2 = read_env(a,
"sigma2",
"rho2");
1214 const double theta = a.number<
double>(
"theta");
1215 const bool hasDelta = a.has(
"delta");
1216 const double delta = hasDelta ? a.number<
double>(
"delta") : 0.0;
1223 static Json run(Args& a) {
1224 const snc::Env arv = read_env(a,
"sigmaA",
"rhoA");
1225 const snc::Env srv = read_env(a,
"sigmaS",
"rhoS");
1226 const double theta = a.number<
double>(
"theta");
1241 static Json run(Args& a) {
1242 const std::size_t n = a.count(
"n");
1255struct OpCtmcSimulate {
1257 static Json run(Args& a) {
1258 const Matrix<T> Q = a.matrix<T>(
"Q");
1259 const std::vector<T> pi0 = a.vector_or_empty<T>(
"pi0");
1260 const std::size_t n = a.count(
"n");
1266 out[
"sts"] = encode_indices(p.states);
1334 const std::string
sn =
1335 "it takes a NetworkStruct; build the model and run line-cli -s ctmc -a <analysis> "
1338 t[
"ctmc_ssg_reachability"] =
sn;
1339 t[
"ctmc_state_space_logsize"] =
sn;
1340 t[
"npfqn_traffic_split_rr"] =
1341 "it takes a NetworkStruct; build the model and run line-cli -s <solver> -a <analysis> "
1343 t[
"npfqn_traffic_idc_at"] =
1344 "it evaluates two caller-supplied IDC functions (a0IdcFun and sIdcFun), which are "
1345 "callables with no JSON form.";
1346 const std::string
env =
1347 "its arrival and service envelopes are functions of theta (e.g. snc_env_poisson as a "
1348 "handle), callables with no JSON form; the envelope values at one theta are exposed "
1349 "through the snc_env_* and snc_srv_* entries.";
1350 t[
"snc_bound_backlog"] =
env;
1351 t[
"snc_bound_delay"] =
env;
1352 t[
"snc_perc_backlog"] =
env;
1353 t[
"snc_perc_delay"] =
env;
1354 t[
"snc_mean_backlog"] =
env;
1355 t[
"snc_mean_delay"] =
env;
1357 "its objective is a function of theta passed as a callable, which has no JSON form.";
Internal to the –api dispatcher: what a per-domain translation unit needs to add entries to the table...
Named-argument reader over the parsed JSON object.
Accumulated state probabilities L(t) = int_0^t pi(s) ds of a CTMC by uniformisation (Reibman and Triv...
Classical stationary iterative solvers for pi Q = 0, sum(pi) = 1: the power method on the uniformised...
Grassmann-Taksar-Heyman (GTH) elimination for the stationary vector, and the limit matrix J = lim exp...
Feasibility predicates for generators and stochastic matrices.
Host-aware memory pre-gate for SolverCTMC.
First passage times into a target STATE SET, for Markov and semi-Markov chains.
Random infinitesimal generator of a CTMC.
Sample path of a continuous-time Markov chain given its generator.
Stochastically stable distribution of a perturbed Markov chain (Wicks 2009).
Normalizing constants of a discrete-time closed cycle of Bernoulli servers.
Equilibrium distribution of a discrete-time Markov chain, and stochastic complementation.
Discrete-time transient distributions, hitting times and uniformization.
DtNcLdResult< T > dpfqn_ncld(const std::vector< std::vector< T > > &P, std::size_t N)
Theorem 3.2 for a cycle whose service probabilities depend on the local queue length.
DtNcResult< T > dpfqn_nc(const std::vector< T > &p, std::size_t N)
Propositions 3.18 and 3.19 for a cycle with state independent service probabilities.
std::vector< std::complex< double > > ctmc_passage_lst(const Matrix< T > &Q, const std::vector< T > &pi0, const std::vector< std::size_t > &target, const std::vector< std::complex< double > > &s)
L(s) = alpha (sI-S)^{-1} s0 + atom at the (complex) points s.
PassageMoments< T > ctmc_passage_moments(const Matrix< T > &Q, const std::vector< T > &pi0, const std::vector< std::size_t > &target, std::size_t nmax=1)
Moments of order 1..nmax of the first passage time into target.
Matrix< T > ctmc_cesaro(const Matrix< T > &Q)
Limit matrix J = lim expm(Q t) of any finite CTMC (Agaev-Chebotarev 2000).
std::vector< double > ctmc_ssd(const Matrix< double > &Cin, const Matrix< double > &Rin)
Stochastically stable distribution, rates C(i,j) eps^R(i,j) (Wicks 2009).
StochCompResult< T > ctmc_stochcomp(const Matrix< T > &Q, const std::vector< std::size_t > &I)
CtmcGateResult ctmc_memory_gate(double log_nstates, bool force=false, double safety_fraction=CTMC_DEFAULT_SAFETY_FRACTION, bool verbose=false)
Decide whether a state space of log-size log_nstates can be solved here.
UniformizationResult< T > ctmc_uniformization(const std::vector< T > &pi0, const Matrix< T > &Q, const T &t, double tol=1e-12, long maxiter=-1)
Transient distribution of a CTMC by uniformization (Jensen's method), and the time-averaged distribut...
PassageCurve< T > ctmc_passage_time(const Matrix< T > &Q, const std::vector< T > &pi0, const std::vector< std::size_t > &target, const std::vector< double > &tset, const std::string &method="expm", const std::string <i_method="euler")
CDF and density of the first passage time on the grid tset: F(t) = 1 - alpha exp(St) 1 and f(t) = alp...
Matrix< T > ctmc_rand(std::size_t n, Gen &gen)
Random infinitesimal generator of a CTMC.
std::vector< T > dtmc_hitting_time(const Matrix< T > &P, const std::vector< std::size_t > &target)
Expected number of steps to reach the target set, zero on the target set itself.
TimeAverageResult< T > ctmc_timeaverage(const std::vector< T > &pi0, const Matrix< T > &Q, const T &t, double tol=1e-12, long maxiter=-1)
Time-averaged distribution (1/t) int_0^t pi(u) du, plus pi(t) itself.
GthResult< T > ctmc_gth_flag(const Matrix< T > &Q)
Stationary vector of a CTMC by GTH elimination, with a flag.
PassagePh< T > ctmc_passage_ph(const Matrix< T > &Q, const std::vector< T > &pi0, const std::vector< std::size_t > &target)
Phase-type representation of the first passage time from pi0 into target.
bool ctmc_isfeasible(const Matrix< T > &Q, const T &tol)
True when Q is square, has nonnegative off-diagonals, nonpositive diagonal and zero row sums.
constexpr long CLASSICAL_DEFAULT_MAXITER
PassageTabooMoments< T > ctmc_passage_taboo_moments(const Matrix< T > &Q, const std::vector< T > &pi0, const std::vector< std::size_t > &target, const std::vector< std::size_t > &taboo, std::size_t nmax=1)
Moments of order 1..nmax of the first passage time into target, CONDITIONAL on entering it before tab...
CtmcPath< T > ctmc_simulate(const Matrix< T > &Q, const std::vector< T > &pi0, std::size_t n, pfqn::McRng &rng)
Simulate n steps of the CTMC with generator Q.
PassageTaboo< T > ctmc_passage_taboo(const Matrix< T > &Q, const std::vector< T > &pi0, const std::vector< std::size_t > &target, const std::vector< std::size_t > &taboo, const std::vector< double > &tset=std::vector< double >(), const std::string &method="expm", const std::string <i_method="euler")
First passage into target under the taboo set taboo, the reference's ctmc_passage_taboo.
Matrix< T > dtmc_transient(const Matrix< T > &P, const std::vector< T > &pi0, std::size_t steps)
Trajectory of the law over steps transitions, row k holding pi0 P^k.
std::vector< T > ctmc_hitting_time(const Matrix< T > &Q, const std::vector< std::size_t > &target)
Mean time to reach any state in target from each state of a CTMC.
AccumulatedResult< T > ctmc_accumulated(const std::vector< T > &pi0, const Matrix< T > &Q, const std::vector< T > &t, double tol=1e-12, long maxiter=-1)
Accumulated state probabilities int_0^t pi(s) ds at each time point.
constexpr double CLASSICAL_DEFAULT_TOL
Merge
Merge rule, MATLAB's config.merge.
@ Interpos
'interpos', lumped interleaving of per-flow M3PP(2, m) fits
@ Default
'default', identical to 'super'
@ Mixture
'mixture', superpose then refit with mmap_mixture_fit_mmap
TrafficIdcContext< T > npfqn_traffic_idc(const std::vector< T > &lambda0, const Matrix< T > &P, const std::vector< T > &c2a0, const std::vector< T > &mu, const std::vector< T > &cs2, const TrafficIdcCorrections &corrections)
Traffic variability equations of the Robust Queueing Network Analyzer (W.
T npfqn_rqna_weight(const T &t)
Canonical reflected-Brownian-motion correlation weight w*(t) used by the Robust Queueing Network Anal...
SqdResult< T > npfqn_sqd(const std::vector< T > &ST, const std::vector< T > &V, const std::vector< T > &cap, const std::vector< bool > &isDelay, const Matrix< T > &rt, const std::vector< std::size_t > &stationToStateful, std::size_t nclasses, int N, const SqdOptions< T > &opt)
Smith Queue Decomposition (SQD): approximate MVA for closed networks under Blocking-After-Service (ma...
NonexpApproxResult< T > npfqn_nonexp_approx(const std::string &method, const std::vector< bool > &isFCFS, const Matrix< T > &rates, const Matrix< T > &ST, const Matrix< T > &V, const Matrix< T > &SCV, const Matrix< T > &Tput, const Matrix< T > &U, const std::vector< T > &gamma, const std::vector< T > &nservers)
Handler for non-exponential service and arrival processes in AMVA and NC.
mam::Mmap< T > npfqn_traffic_merge_cs(const std::vector< mam::Mmap< T > > &flows, const Matrix< T > &prob, Merge merge=Merge::Default)
Merge flows that switch class on departure.
std::vector< Mmap< T > > npfqn_traffic_split_cs(const Mmap< T > &MMAP, const Matrix< T > &P)
Splitting of a marked MAP departure flow with class switching.
FeedbackElimResult< T > npfqn_feedback_elim(const Matrix< T > &P, const std::vector< T > &rho, const std::vector< T > &cs2=std::vector< T >(), const std::vector< T > &lambda=std::vector< T >(), bool immediateOnly=false)
Near-immediate feedback elimination for the robust queueing network analyzer.
BndBpt< T > npfqn_bnd_bpt(const std::vector< T > &lambda0, const std::vector< T > &mu, const Matrix< T > &P, const std::vector< std::size_t > &stationOf, const std::vector< T > &c)
First-order linear-programming relaxation of the achievable region of a multiclass open Markovian que...
TrafficRqt< T > npfqn_traffic_rqt(const std::vector< T > &lambda0, const std::vector< T > &Gamma0, const std::vector< T > &alpha0, const Matrix< T > &F)
Effective arrival processes of a network under the Robust Queueing calculus.
Compress
Post-merge compression, MATLAB's config.compress.
@ Default
'default', mmap_compress with its own default method
std::vector< Matrix< T > > Mmap
An MMAP as the MATLAB cell {D0, D1, D1^(1), ..., D1^(R)}.
BndBgt< T > npfqn_bnd_bgt(const std::vector< T > &lambda, const std::vector< std::vector< T > > &mu, const std::vector< std::vector< std::size_t > > &sigma, std::size_t J)
Piecewise-linear Lyapunov UPPER bound on the steady-state queue lengths of a multitype (deterministic...
DpsMorrisonResult< T > npfqn_dps_morrison(const std::vector< T > &N, const std::vector< T > &Z, const std::vector< T > &S, const std::vector< T > &w)
Evaluates Morrison's two-term approximation.
mam::Mmap< T > npfqn_traffic_merge(const std::vector< mam::Mmap< T > > &flows, const MergeConfig &config=MergeConfig())
Merge a list of MMAPs carrying the same classes.
std::mt19937_64 McRng
The generator type every Monte Carlo entry point in this tree accepts.
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.
Json encode_vectors(const std::vector< std::vector< T > > &v)
A list of vectors, the shape a per-class or per-segment result returns.
Matrix< T > matrix_from_json(const Json &j, const std::string &where)
A matrix from a JSON value: 2-D array as rows, 1-D array as a row vector, scalar as 1x1,...
Json encode_matrices(const std::vector< Matrix< T > > &v)
A list of matrices, the shape the MMAP/BMAP families return as {D0,D1,...}.
void register_library_only_mc(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 decimal_text(const Json &j, const std::string &where)
The decimal literal behind a JSON scalar, per the policy in the file header.
void register_api_mc(DispatchTable &t)
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.
std::map< std::string, Invoker > DispatchTable
Env snc_leftover(const Env &srv, const Env &cross)
Leftover service envelope under blind (arbitrary) multiplexing.
Env snc_conv(const Env &s1, const Env &s2, double theta, double delta=-1.0)
Min-plus convolution of two service envelopes (tandem concatenation).
Env snc_output(const Env &arv, const Env &srv, double theta)
Output (departure) arrival envelope of a flow leaving a server.
Env snc_srv_exp(double mu, double theta)
MGF service envelope of an exponential server, in JOB units.
Env snc_env_map(const Matrix< double > &D0, const Matrix< double > &D1, double theta)
MGF arrival envelope of a MAP/MMPP flow with unit-size jobs.
Env snc_srv_rate(double C)
MGF service envelope of a constant-rate work-conserving server.
Env snc_env_tokenbucket(double b, double r)
Deterministic token-bucket arrival envelope.
Env snc_env_poisson(double lambda, double theta)
MGF arrival envelope of a Poisson flow with unit-size jobs.
Env snc_env_cpoisson(double lambda, double mu, double theta)
MGF arrival envelope of a compound Poisson flow with Exp job sizes.
Conservation laws of a layered queueing network, enumerated from its structure.
Piecewise-linear Lyapunov UPPER bound on the steady-state queue lengths of a multitype (deterministic...
First-order linear-programming relaxation of the achievable region of a multiclass open Markovian que...
Two-term heavy-usage asymptotic approximation for a closed queueing network with one infinite-server ...
Near-immediate feedback elimination for the robust queueing network analyzer.
Handler for non-exponential service and arrival processes in AMVA and NC.
Canonical reflected-Brownian-motion correlation weight w*(t) used by the Robust Queueing Network Anal...
Smith Queue Decomposition (SQD): approximate MVA for closed networks under Blocking-After-Service (ma...
Traffic variability equations of the Robust Queueing Network Analyzer (W.
Superposition of several marked arrival flows into one.
Merge of marked arrival flows with class switching.
Effective arrival processes of a network under the Robust Queueing calculus.
Splitting of a marked MAP departure flow with class switching.
Min-plus convolution of two service envelopes (tandem concatenation).
MGF arrival envelope of a compound Poisson flow with Exp job sizes.
MGF arrival envelope of a MAP/MMPP flow with unit-size jobs.
MGF arrival envelope of a Poisson flow with unit-size jobs.
Deterministic token-bucket arrival envelope.
Leftover service envelope under blind (arbitrary) multiplexing.
Output (departure) arrival envelope of a flow leaving a server.
MGF service envelope of an exponential server, in JOB units.
MGF service envelope of a constant-rate work-conserving server.