5#ifndef LINE_SOLVERS_WRAPPERS_JMT_JMT_LOGS_H
6#define LINE_SOLVERS_WRAPPERS_JMT_JMT_LOGS_H
89 const std::vector<bool>& is_node_logged,
90 const std::string& log_path) {
91 const std::size_t N =
sn.nodes.size(), K =
sn.classes.size();
92 if (is_node_logged.size() != N)
93 throw InputError(
"linkAndLog: the isNodeLogged vector does not match the node count");
94 std::vector<bool> logged = is_node_logged;
95 for (std::size_t i = 0; i < N; ++i)
107 std::vector<std::size_t> arv(N + 1, 0), dep(N + 1, 0);
108 for (std::size_t i = 1; i <= N; ++i) {
109 if (!logged[i - 1])
continue;
124 out.
nodes[nd - 1].routing_weights.assign(K, std::map<std::size_t, double>());
125 out.
nodes[nd - 1].routing_param.assign(K, 0);
126 out.
nodes[nd - 1].logger.file_name =
sn.nodes[i - 1].name +
"-Arv.csv";
127 out.
nodes[nd - 1].logger.file_path = log_path;
130 for (std::size_t i = 1; i <= N; ++i) {
131 if (!logged[i - 1])
continue;
136 out.
nodes[nd - 1].routing_weights.assign(K, std::map<std::size_t, double>());
137 out.
nodes[nd - 1].routing_param.assign(K, 0);
138 out.
nodes[nd - 1].logger.file_name =
sn.nodes[i - 1].name +
"-Dep.csv";
139 out.
nodes[nd - 1].logger.file_path = log_path;
145 for (
const auto& kv :
sn.P) {
146 const std::size_t r = kv.first.first, s = kv.first.second;
148 for (std::size_t i = 1; i <= N && i <= B.
rows(); ++i)
149 for (std::size_t j = 1; j <= N && j <= B.
cols(); ++j) {
150 if (B(i - 1, j - 1) == zero)
continue;
151 const std::size_t from = logged[i - 1] ? dep[i] : i;
152 const std::size_t to = logged[j - 1] ? arv[j] : j;
153 out.
set_route(r, s, from, to, B(i - 1, j - 1));
158 for (std::size_t i = 1; i <= N; ++i) {
159 if (!logged[i - 1])
continue;
160 for (std::size_t r = 1; r <= K; ++r) {
172inline std::vector<std::string> split_semi(
const std::string&
line) {
173 std::vector<std::string> out;
176 const std::size_t e =
line.find(
';', b);
177 out.push_back(
line.substr(b, e == std::string::npos ? std::string::npos : e - b));
178 if (e == std::string::npos)
break;
188 std::vector<double>
ts;
190 std::vector<std::string>
cls;
205 std::ifstream f(path.c_str());
206 if (!f)
throw InputError(
"SolverJMT: cannot read the JMT log '" + path +
"'");
210 while (std::getline(f,
line)) {
215 if (
line.empty())
continue;
216 const std::vector<std::string> col = detail::split_semi(
line);
217 if (col.
size() < 4)
continue;
218 out.
ts.push_back(std::strtod(col[1].c_str(),
nullptr));
219 out.
job.push_back(std::strtod(col[2].c_str(),
nullptr));
220 out.
cls.push_back(col[3]);
228 std::vector<double>
t;
229 std::vector<std::vector<double>>
qlen;
248 const std::vector<std::size_t>& class_of_arv,
249 const std::vector<std::size_t>& class_of_dep,
250 const std::vector<double>& node_preload) {
251 const std::size_t K = node_preload.size();
254 std::vector<double> delta;
259 std::vector<Row> rows;
260 rows.reserve(arv.
ts.size() + dep.
ts.size());
261 for (std::size_t i = 0; i < arv.
ts.size(); ++i) {
264 r.delta.assign(K, 0.0);
265 if (class_of_arv[i] >= 1 && class_of_arv[i] <= K) r.delta[class_of_arv[i] - 1] = +1.0;
267 r.cls = class_of_arv[i];
271 for (std::size_t i = 0; i < dep.
ts.size(); ++i) {
274 r.delta.assign(K, 0.0);
275 if (class_of_dep[i] >= 1 && class_of_dep[i] <= K) r.delta[class_of_dep[i] - 1] = -1.0;
277 r.cls = class_of_dep[i];
284 std::stable_sort(rows.begin(), rows.end(),
285 [](
const Row& a,
const Row& b) { return a.t < b.t; });
287 for (std::size_t ev = 1; ev < rows.size(); ++ev) {
288 if (rows[ev].t != rows[ev - 1].t)
continue;
289 const double j = rows[ev].job;
290 std::size_t prev = 0;
291 bool has_prev =
false;
292 for (std::size_t k = ev; k > 0; --k)
293 if (rows[k - 1].job == j) {
298 if (!has_prev)
continue;
299 if (rows[prev].type != rows[ev].type)
continue;
300 std::size_t next = 0;
301 bool has_next =
false;
302 for (std::size_t k = ev + 1; k < rows.size(); ++k)
303 if (rows[k].job == j) {
308 if (!has_next)
continue;
309 std::swap(rows[ev], rows[next]);
313 out.
t.push_back(0.0);
314 out.
qlen.push_back(node_preload);
319 out.
event.push_back(init);
320 std::vector<double> run = node_preload;
321 for (std::size_t i = 0; i < rows.size(); ++i) {
322 for (std::size_t r = 0; r < K; ++r) run[r] += rows[i].delta[r];
323 out.
t.push_back(rows[i].t);
324 out.
qlen.push_back(run);
327 e.
type = rows[i].type;
330 out.
event.push_back(e);
347 const std::vector<std::size_t>& class_of_dep) {
353 std::map<double, std::vector<Ev>> by_job;
354 for (std::size_t i = 0; i < arv.
ts.size(); ++i)
355 by_job[arv.
job[i]].push_back(Ev{arv.ts[i], true, class_of_arv[i]});
356 for (std::size_t i = 0; i < dep.
ts.size(); ++i)
357 by_job[dep.
job[i]].push_back(Ev{dep.ts[i], false, class_of_dep[i]});
359 std::map<std::size_t, std::vector<double>> out;
360 for (
auto& kv : by_job) {
361 std::vector<Ev>& evs = kv.second;
362 std::stable_sort(evs.begin(), evs.end(),
363 [](
const Ev& a,
const Ev& b) { return a.t < b.t; });
365 while (i + 1 < evs.size()) {
366 if (!evs[i].is_arv) {
370 if (evs[i + 1].is_arv) {
377 out[evs[i].cls].push_back(evs[i + 1].t - evs[i].t);
400 const std::vector<bool>& is_node_logged,
401 const std::string& log_path) {
402 std::map<std::string, std::size_t> class_of;
403 for (std::size_t r = 1; r <= orig.
nclasses; ++r) class_of[orig.
classes[r - 1].name] = r;
405 std::map<std::size_t, JmtNodeTrace<T>> out;
406 for (std::size_t ind = 1; ind <= orig.
nodes.size(); ++ind) {
407 if (!is_node_logged[ind - 1])
continue;
408 const std::string base = log_path +
"/" + orig.
nodes[ind - 1].name;
409 const std::string fa = base +
"-Arv.csv", fd = base +
"-Dep.csv";
410 if (!detail::is_file(fa) || !detail::is_file(fd))
continue;
412 std::vector<std::size_t> ca(arv.
cls.size(), 0), cd(dep.cls.size(), 0);
413 for (std::size_t i = 0; i < arv.
cls.size(); ++i) {
414 const auto it = class_of.find(arv.
cls[i]);
415 ca[i] = it == class_of.end() ? 0 : it->second;
417 for (std::size_t i = 0; i < dep.cls.size(); ++i) {
418 const auto it = class_of.find(dep.cls[i]);
419 cd[i] = it == class_of.end() ? 0 : it->second;
421 std::vector<double> preload(orig.
nclasses, 0.0);
422 const std::size_t ist = orig.
nodes[ind - 1].station;
426 for (std::size_t r = 0; r < orig.
nclasses && r < im->second.size(); ++r)
429 for (std::size_t r = 0; r < orig.
nclasses; ++r) {
430 const double n = orig.
classes[r].population;
431 if (std::isfinite(n) && orig.
classes[r].refstat == ist) preload[r] = n;
452 if (node == 0 || node >
sn.nodes.size())
453 throw InputError(
"SolverJMT: sampleAggr was given a node index out of range");
454 std::vector<bool> logged(
sn.nodes.size(),
false);
455 logged[node - 1] =
true;
461 if (num_events > 0) o.
max_events =
static_cast<double>(num_events *
sn.nodes.size() *
sn.classes.size());
464 const auto it = traces.find(node);
465 if (it == traces.end())
467 "SolverJMT: the simulation produced no log for node '" +
sn.nodes[node - 1].name +
468 "'; the run has likely failed before any job crossed it");
470 if (num_events > 0 &&
tr.t.size() > num_events + 1) {
471 tr.t.resize(num_events + 1);
472 tr.qlen.resize(num_events + 1);
473 std::vector<JmtEvent> ev;
474 for (std::size_t i = 0; i <
tr.event.size(); ++i)
475 if (
tr.event[i].t <=
tr.t.back()) ev.push_back(
tr.event[i]);
484 std::vector<double>
t;
486 std::vector<std::vector<std::vector<double>>>
state;
503 std::vector<bool> logged(
sn.nodes.size(),
false);
504 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
505 const std::size_t ind =
sn.station_to_node[ist - 1];
515 if (num_events == 0) num_events =
static_cast<std::size_t
>(
opt.samples);
516 o.
max_events =
static_cast<double>((num_events - 1) *
sn.nodes.size() *
sn.classes.size());
521 std::set<double> grid;
522 double tmax = std::numeric_limits<double>::infinity();
523 for (
const auto& kv : traces) {
524 if (kv.second.t.empty())
continue;
525 tmax = std::min(tmax, kv.second.t.back());
526 for (
double t : kv.second.t) grid.insert(t);
528 for (
double t : grid)
529 if (t <= tmax) out.
t.push_back(t);
531 out.
state.assign(
sn.nstations, std::vector<std::vector<double>>());
532 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
533 const std::size_t ind =
sn.station_to_node[ist - 1];
534 const auto it = traces.find(ind);
535 if (it == traces.end())
continue;
537 std::vector<std::vector<double>> block(out.
t.size(),
538 std::vector<double>(
sn.nclasses, 0.0));
540 for (std::size_t g = 0; g < out.
t.size(); ++g) {
541 while (k + 1 <
tr.t.size() &&
tr.t[k + 1] <= out.
t[g]) ++k;
542 if (k <
tr.qlen.size()) block[g] =
tr.qlen[k];
544 out.
state[ist - 1] = block;
546 for (
const auto& kv : traces)
547 for (std::size_t i = 0; i < kv.second.event.size(); ++i) {
550 if (e.
t <= (out.
t.empty() ? 0.0 : out.
t.back())) out.
event.push_back(e);
552 std::stable_sort(out.
event.begin(), out.
event.end(),
572std::map<std::pair<std::size_t, std::size_t>, std::vector<std::pair<double, double>>>
574 bool seed_from_steady =
true) {
575 std::vector<bool> logged(
sn.nodes.size(),
false);
577 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
578 const std::size_t ind =
sn.station_to_node[ist - 1];
579 for (std::size_t r = 1; r <=
sn.nclasses; ++r)
581 logged[ind - 1] =
true;
586 if (seed_from_steady) {
593 std::vector<std::vector<double>> n(
sn.nstations,
594 std::vector<double>(
sn.nclasses, 0.0));
595 for (std::size_t r = 1; r <=
sn.nclasses; ++r) {
596 double tot = 0.0, vmax = -1.0;
597 std::size_t imax = 1;
598 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
599 const double q = std::floor(std::max(
601 n[ist - 1][r - 1] = q;
608 const double njobs =
sn.classes[r - 1].population;
609 if (std::isfinite(njobs) && tot < njobs)
610 n[imax - 1][r - 1] += njobs - tot;
612 for (std::size_t ist = 1; ist <= inst.
nstations && ist <=
sn.nstations; ++ist) {
616 std::vector<T> row(
sn.nclasses);
617 for (std::size_t r = 0; r <
sn.nclasses; ++r)
624 std::map<std::string, std::size_t> class_of;
625 for (std::size_t r = 1; r <=
sn.nclasses; ++r) class_of[
sn.classes[r - 1].name] = r;
627 std::map<std::pair<std::size_t, std::size_t>, std::vector<std::pair<double, double>>> out;
628 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
629 const std::size_t ind =
sn.station_to_node[ist - 1];
630 if (!logged[ind - 1])
continue;
631 const std::string base = logs.
path() +
"/" +
sn.nodes[ind - 1].name;
632 if (!detail::is_file(base +
"-Arv.csv") || !detail::is_file(base +
"-Dep.csv"))
continue;
635 std::vector<std::size_t> ca(arv.
cls.size(), 0), cd(dep.
cls.size(), 0);
636 for (std::size_t i = 0; i < arv.
cls.size(); ++i) {
637 const auto it = class_of.find(arv.
cls[i]);
638 ca[i] = it == class_of.end() ? 0 : it->second;
640 for (std::size_t i = 0; i < dep.
cls.size(); ++i) {
641 const auto it = class_of.find(dep.
cls[i]);
642 cd[i] = it == class_of.end() ? 0 : it->second;
644 const std::map<std::size_t, std::vector<double>> samples =
646 for (
const auto& kv : samples) {
647 if (kv.first == 0 || kv.second.empty())
continue;
648 std::vector<double> x = kv.second;
649 std::sort(x.begin(), x.end());
652 std::vector<std::pair<double, double>> fx;
653 fx.push_back(std::make_pair(0.0, x.front()));
655 while (i < x.size()) {
657 while (j + 1 < x.size() && x[j + 1] == x[i]) ++j;
658 fx.push_back(std::make_pair(
static_cast<double>(j + 1) /
659 static_cast<double>(x.size()),
663 out[std::make_pair(ist, kv.first)] = fx;
682 if (
opt.method !=
"default" &&
opt.method !=
"jsim")
684 "SolverJMT: " + what +
" is estimated from simulated JSIM sample paths, and method '" +
685 opt.method +
"' logs no trajectory; use 'default' (the ensemble over "
686 "options.config.replications runs) or 'jsim' (one run)");
687 if (
opt.method ==
"jsim")
return 1;
688 if (
opt.replications < 1)
689 throw InputError(
"SolverJMT: options.config.replications is a positive count of independent "
690 "runs (got " + std::to_string(
opt.replications) +
")");
691 return static_cast<std::size_t
>(
opt.replications);
708 std::vector<std::vector<double>>& states_out) {
710 if (!std::isfinite(
opt.max_simulated_time))
712 "SolverJMT: getTranProbAggr requires a finite time span, e.g. "
713 "options.timespan = [0, T]");
714 if (station == 0 || station >
sn.nstations)
715 throw InputError(
"SolverJMT: getTranProbAggr was given a station index out of range");
716 const std::size_t ind =
sn.station_to_node[station - 1];
718 throw InputError(
"SolverJMT: getTranProbAggr does not apply to a Source");
720 std::vector<JmtSysTrace<T>> runs;
721 std::set<double> grid;
722 for (std::size_t it = 0; it < replications; ++it) {
724 o.
seed =
opt.seed +
static_cast<long>(it);
726 for (
double t :
tr.t) grid.insert(t);
729 std::vector<double> tu(grid.begin(), grid.end());
733 std::map<std::vector<double>, std::size_t> index;
734 std::vector<std::vector<double>> states;
735 std::vector<std::vector<std::size_t>> occupied(runs.size(),
736 std::vector<std::size_t>(tu.size(), 0));
737 for (std::size_t r = 0; r < runs.size(); ++r) {
738 const std::vector<std::vector<double>>& block = runs[r].state[station - 1];
739 if (block.
empty())
continue;
741 for (std::size_t g = 0; g < tu.size(); ++g) {
742 while (k + 1 < runs[r].t.size() && runs[r].t[k + 1] <= tu[g]) ++k;
743 if (k >= block.
size())
continue;
744 const std::vector<double>& s = block[k];
745 auto it = index.find(s);
746 if (it == index.end()) {
747 index[s] = states.size();
751 occupied[r][g] = it->second + 1;
754 std::vector<std::vector<double>> pi(tu.size(), std::vector<double>(states.size(), 0.0));
755 for (std::size_t r = 0; r < runs.size(); ++r)
756 for (std::size_t g = 0; g < tu.size(); ++g)
757 if (occupied[r][g] != 0)
758 pi[g][occupied[r][g] - 1] += 1.0 /
static_cast<double>(runs.size());
760 return std::make_pair(tu, pi);
773 std::vector<double> dt(t.size(), 0.0);
774 for (std::size_t i = 0; i + 1 < t.size(); ++i) dt[i] = t[i + 1] - t[i];
817 std::size_t target_station = 0,
818 const std::vector<double>& target = std::vector<double>()) {
820 if (!target.empty()) {
821 if (target_station == 0 || target_station >
sn.nstations)
822 throw InputError(
"SolverJMT: getProbAggr was given a station index out of range");
823 if (target.size() !=
sn.nclasses)
824 throw InputError(
"SolverJMT: getProbAggr takes one job count per class (" +
825 std::to_string(
sn.nclasses) +
"), got " +
826 std::to_string(target.size()));
827 for (std::size_t r = 0; r <
sn.nclasses; ++r)
830 std::vector<std::vector<double>> nir(
sn.nstations, std::vector<double>(
sn.nclasses, 0.0));
831 for (std::size_t i = 0; i <
sn.nstations; ++i)
832 for (std::size_t r = 0; r <
sn.nclasses; ++r)
841 std::vector<double> hit(
sn.nstations, 0.0);
842 double sys_hit = 0.0, total = 0.0;
843 for (std::size_t g = 0; g < dt.size(); ++g) {
846 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
847 const std::size_t ind =
sn.station_to_node[ist - 1];
851 const std::vector<std::vector<double>>& block =
tr.state[ist - 1];
852 bool same = g < block.
size();
853 for (std::size_t r = 0; r <
sn.nclasses && same; ++r)
854 same = block[g][r] == nir[ist - 1][r];
856 hit[ist - 1] += dt[g];
864 if (dt[g] > 0.0) out.
sys_seen =
true;
871 "SolverJMT: the simulation produced no observed dwell time, so no state probability "
872 "can be estimated from it");
873 out.
sys = sys_hit / total;
874 for (std::size_t i = 0; i <
sn.nstations; ++i) out.
station[i] = hit[i] / total;
881 std::vector<double>
t;
883 std::vector<std::vector<std::vector<double>>>
QNt;
884 std::vector<std::vector<std::vector<double>>>
UNt;
885 std::vector<std::vector<std::vector<double>>>
TNt;
915 if (!std::isfinite(
opt.max_simulated_time))
916 throw InputError(
"SolverJMT: the transient averages need a finite timespan; a transient mean "
917 "over an unstated horizon is not a quantity");
921 if (!refusal.empty())
throw InputError(refusal);
924 std::vector<JmtSysTrace<T>> paths;
925 std::set<double> grid;
926 double tumax = std::numeric_limits<double>::infinity();
927 for (std::size_t it = 0; it < reps; ++it) {
930 o.
seed =
opt.seed +
static_cast<long>(it);
934 }
catch (
const std::exception&) {
937 if (
tr.t.empty())
continue;
938 tumax = std::min(tumax,
tr.t.back());
939 for (
double tv :
tr.t) grid.insert(tv);
944 "SolverJMT: no valid replications produced; the transient averages cannot be computed");
947 out.valid = paths.size();
948 for (
double tv : grid)
949 if (tv <= tumax) out.t.push_back(tv);
950 const std::size_t nt = out.t.size();
951 const std::size_t M =
sn.nstations, K =
sn.nclasses;
952 out.QNt.assign(M, std::vector<std::vector<double>>(K, std::vector<double>(nt, 0.0)));
953 out.UNt.assign(M, std::vector<std::vector<double>>(K, std::vector<double>(nt, 0.0)));
954 out.TNt.assign(M, std::vector<std::vector<double>>(K, std::vector<double>(nt, 0.0)));
956 const double inv = 1.0 /
static_cast<double>(paths.size());
957 for (std::size_t ist = 0; ist < M; ++ist) {
959 const bool finite_c = std::isfinite(c) && c > 0.0;
961 if (ist >=
tr.state.size() ||
tr.state[ist].empty())
continue;
962 const std::vector<std::vector<double>>& block =
tr.state[ist];
964 for (std::size_t g = 0; g < nt; ++g) {
965 while (k + 1 <
tr.t.size() &&
tr.t[k + 1] <= out.t[g]) ++k;
966 if (out.t[g] <
tr.t.front() || k >= block.
size())
continue;
967 for (std::size_t r = 0; r < K && r < block[k].
size(); ++r) {
968 const double n = block[k][r];
969 out.QNt[ist][r][g] += inv * n;
970 out.UNt[ist][r][g] += inv * (finite_c ? std::min(n, c) / c : n);
977 for (std::size_t r = 0; r < K; ++r) {
980 const double lambda = (std::isfinite(mu) && mu > 0.0) ? mu : 0.0;
981 for (std::size_t g = 0; g < nt; ++g) out.TNt[ist][r][g] = lambda;
984 const double scale = std::isfinite(mu) ? (finite_c ? c * mu : mu) : 0.0;
985 for (std::size_t g = 0; g < nt; ++g) out.TNt[ist][r][g] = out.UNt[ist][r][g] * scale;
ExternalError(const std::string &what)
NumericError(const std::string &what)
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
void set_route(std::size_t r, std::size_t s, std::size_t i, std::size_t j, const T &p)
P{r,s}(i,j) = p, with 1-based NODE and class indices.
std::map< std::pair< std::size_t, std::size_t >, Matrix< T > > P
P[(r,s)] is an (nnodes x nnodes) block; absent means all zero.
std::size_t add_node(const std::string &nm, NodeType ty, bool stateful)
Add a non-station node (a Fork, a Router).
std::vector< JobClass > classes
void refresh_struct()
The whole chain, in MATLAB's refreshStruct order.
std::map< std::pair< std::size_t, std::size_t >, Matrix< T > > Peff
The routing after refresh_routing() has expanded the non-PROB strategies and folded the class switche...
std::vector< NodeDef > nodes
every node, in creation order
std::string log_path
Network.setLogPath / getLogPath: the directory every Logger writes into, and the logPath attribute of...
std::map< std::size_t, std::vector< T > > initmarking
The DECLARED initial state of a stateful node, by 1-based node index.
std::vector< std::size_t > station_to_node
(nstations) 1-based node index
void keep()
Leave the directory in place, for a caller that wants to inspect it.
const std::string & path() const
The directory itself, with no trailing separator.
The exception types the port throws.
Matrix< T > sn_declared_marginal(const qn::NetworkStruct< T > &sn)
The (nstations x nclasses) per-class job counts of the model's OWN state.
bool jmt_metric_enabled(const qn::NetworkStruct< T > &sn, JmtMetricKind kind, std::size_t ist, std::size_t r, const std::vector< bool > &is_cache_class)
Port of the disabled rules in getAvgHandles, per (station, class).
std::vector< bool > jmt_cache_classes(const qn::NetworkStruct< T > &sn)
The classes a Cache switches jobs into; they keep their Tput/ArvR measures.
qn::NetworkStruct< T > jmt_link_and_log(const qn::NetworkStruct< T > &sn, const std::vector< bool > &is_node_logged, const std::string &log_path)
Port of @@MNetwork/linkAndLog.m: the model with an arrival and a departure Logger around every logged...
JmtLogFile jmt_read_log(const std::string &path)
Read one JMT log CSV.
JmtReplication< T > jmt_transient_replications(const qn::NetworkStruct< T > &sn, const JmtOptions &opt)
Port of the transient ensemble of @@SolverJMT/runAnalyzer.m (default over a finite timespan).
JmtSysTrace< T > jmt_sample_sys_aggr(const qn::NetworkStruct< T > &sn, std::size_t num_events, const JmtOptions &opt)
Port of sampleSysAggr: every station's trajectory on one time grid.
JmtNodeTrace< T > jmt_sample_aggr(const qn::NetworkStruct< T > &sn, std::size_t node, std::size_t num_events, const JmtOptions &opt)
Port of sampleAggr: the queue-length trajectory of one node.
std::map< std::size_t, std::vector< double > > jmt_parse_tran_resp_t(const JmtLogFile &arv, const JmtLogFile &dep, const std::vector< std::size_t > &class_of_arv, const std::vector< std::size_t > &class_of_dep)
Port of parseTranRespT: the per-class response-time samples of one node.
JmtNodeTrace< T > jmt_parse_tran_state(const JmtLogFile &arv, const JmtLogFile &dep, const std::vector< std::size_t > &class_of_arv, const std::vector< std::size_t > &class_of_dep, const std::vector< double > &node_preload)
Port of parseTranState: the arrival and departure logs merged into a per-class queue-length trajector...
JmtEventType
The event kinds a JMT log carries, MATLAB EventType.
std::size_t jmt_transient_replication_count(const JmtOptions &opt, const std::string &what)
How many JSIM runs a transient estimate is over: the gate the two transient arms share.
JmtResult< T > solver_jmt_run_analyzer(const qn::NetworkStruct< T > &sn, const JmtOptions &opt_in)
Port of @@SolverJMT/runAnalyzer.m, the jsim and jmva arms.
std::map< std::pair< std::size_t, std::size_t >, std::vector< std::pair< double, double > > > jmt_get_cdf_resp_t(const qn::NetworkStruct< T > &sn, const JmtOptions &opt, bool seed_from_steady=true)
Port of getCdfRespT: the empirical response-time distribution per (station, class),...
std::vector< double > jmt_dwell_weights(const std::vector< double > &t)
The dwell-time weights of a trajectory sampled at t.
std::string jmt_removed_method_refusal(const std::string &method)
The migration sentence for a method name SolverJMT no longer has; empty for any other name.
std::pair< std::vector< double >, std::vector< std::vector< double > > > jmt_get_tran_prob_aggr(const qn::NetworkStruct< T > &sn, std::size_t station, const JmtOptions &opt, std::vector< std::vector< double > > &states_out)
Port of getTranProbAggr: the transient distribution of one station's aggregate state,...
JmtProbAggr jmt_prob_aggr(const qn::NetworkStruct< T > &sn, const JmtOptions &opt, std::size_t target_station=0, const std::vector< double > &target=std::vector< double >())
Port of getProbAggr and getProbSysAggr, both off ONE instrumented run.
std::string jmt_method_refusal(const qn::NetworkStruct< T > &sn, const std::string &method, const JmtOptions &opt)
std::map< std::size_t, JmtNodeTrace< T > > jmt_parse_logs(const qn::NetworkStruct< T > &orig, const std::vector< bool > &is_node_logged, const std::string &log_path)
Port of parseLogs: read every logged node's CSV pair.
NodeType
Node kinds, with the values of MATLAB NodeType.
Conservation laws of a layered queueing network, enumerated from its structure.
A queueing network and its refreshed NetworkStruct.
Ports of matlab/src/api/sn/sn_get_state_aggr.m and sn_is_state_valid.m.
Port of SolverJMT, the Java Modelling Tools client.
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
One logged event: when, of which kind, in which class, for which job.
std::size_t cls
1-based class index, 0 at INIT
std::size_t node
1-based node index
double job
JMT's job id, -1 at INIT.
One arrival or departure CSV file, as three parallel columns.
std::vector< double > job
std::vector< std::string > cls
The per-class queue-length trajectory of one node, plus its event stream.
std::vector< std::vector< double > > qlen
(|t| x nclasses) counts after the event
std::vector< JmtEvent > event
std::vector< double > t
event times, ascending
The options of one JMT solve, SolverOptions('JMT') restricted to what is read.
std::string method
default | jsim | jmva | jmva.<alg>
double max_events
JSIM event budget, -1 unlimited; set by the samplers as MATLAB's maxEvents.
What jmt_prob_aggr reports: the system probability and the per-station ones.
std::vector< bool > station_seen
the same, per station
bool sys_seen
whether the joint state occurred at all
double sys
P(the whole network is in the declared state).
std::vector< double > station
P(station i holds its declared per-class counts).
Transient averages over independent replications, on one time grid.
std::vector< std::vector< std::vector< double > > > UNt
std::size_t valid
Replications that produced a usable trajectory.
std::vector< std::vector< std::vector< double > > > TNt
std::vector< std::vector< std::vector< double > > > QNt
QNt[ist-1][r] over t.
The result of a JMT solve: the shared AvgResult plus what only JMT reports.
The system trajectory: one per-class block per station, on a common grid.
std::vector< std::vector< std::vector< double > > > state
state[ist-1] is (|t| x nclasses); a Source's block is empty.
std::vector< JmtEvent > event
A scratch directory for the subprocess wrappers, the port's lineTempName.