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 const auto it = traces.find(node);
462 if (it == traces.end())
464 "SolverJMT: the simulation produced no log for node '" +
sn.nodes[node - 1].name +
465 "'; the run has likely failed before any job crossed it");
467 if (num_events > 0 &&
tr.t.size() > num_events + 1) {
468 tr.t.resize(num_events + 1);
469 tr.qlen.resize(num_events + 1);
470 std::vector<JmtEvent> ev;
471 for (std::size_t i = 0; i <
tr.event.size(); ++i)
472 if (
tr.event[i].t <=
tr.t.back()) ev.push_back(
tr.event[i]);
481 std::vector<double>
t;
483 std::vector<std::vector<std::vector<double>>>
state;
500 std::vector<bool> logged(
sn.nodes.size(),
false);
501 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
502 const std::size_t ind =
sn.station_to_node[ist - 1];
514 std::set<double> grid;
515 double tmax = std::numeric_limits<double>::infinity();
516 for (
const auto& kv : traces) {
517 if (kv.second.t.empty())
continue;
518 tmax = std::min(tmax, kv.second.t.back());
519 for (
double t : kv.second.t) grid.insert(t);
521 for (
double t : grid)
522 if (t <= tmax) out.
t.push_back(t);
523 if (num_events > 0 && out.
t.size() > num_events) out.
t.resize(num_events);
525 out.
state.assign(
sn.nstations, std::vector<std::vector<double>>());
526 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
527 const std::size_t ind =
sn.station_to_node[ist - 1];
528 const auto it = traces.find(ind);
529 if (it == traces.end())
continue;
531 std::vector<std::vector<double>> block(out.
t.size(),
532 std::vector<double>(
sn.nclasses, 0.0));
534 for (std::size_t g = 0; g < out.
t.size(); ++g) {
535 while (k + 1 <
tr.t.size() &&
tr.t[k + 1] <= out.
t[g]) ++k;
536 if (k <
tr.qlen.size()) block[g] =
tr.qlen[k];
538 out.
state[ist - 1] = block;
540 for (
const auto& kv : traces)
541 for (std::size_t i = 0; i < kv.second.event.size(); ++i) {
544 if (e.
t <= (out.
t.empty() ? 0.0 : out.
t.back())) out.
event.push_back(e);
546 std::stable_sort(out.
event.begin(), out.
event.end(),
566std::map<std::pair<std::size_t, std::size_t>, std::vector<std::pair<double, double>>>
568 bool seed_from_steady =
true) {
569 std::vector<bool> logged(
sn.nodes.size(),
false);
571 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
572 const std::size_t ind =
sn.station_to_node[ist - 1];
573 for (std::size_t r = 1; r <=
sn.nclasses; ++r)
575 logged[ind - 1] =
true;
580 if (seed_from_steady) {
587 std::vector<std::vector<double>> n(
sn.nstations,
588 std::vector<double>(
sn.nclasses, 0.0));
589 for (std::size_t r = 1; r <=
sn.nclasses; ++r) {
590 double tot = 0.0, vmax = -1.0;
591 std::size_t imax = 1;
592 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
593 const double q = std::floor(std::max(
595 n[ist - 1][r - 1] = q;
602 const double njobs =
sn.classes[r - 1].population;
603 if (std::isfinite(njobs) && tot < njobs)
604 n[imax - 1][r - 1] += njobs - tot;
606 for (std::size_t ist = 1; ist <= inst.
nstations && ist <=
sn.nstations; ++ist) {
610 std::vector<T> row(
sn.nclasses);
611 for (std::size_t r = 0; r <
sn.nclasses; ++r)
618 std::map<std::string, std::size_t> class_of;
619 for (std::size_t r = 1; r <=
sn.nclasses; ++r) class_of[
sn.classes[r - 1].name] = r;
621 std::map<std::pair<std::size_t, std::size_t>, std::vector<std::pair<double, double>>> out;
622 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
623 const std::size_t ind =
sn.station_to_node[ist - 1];
624 if (!logged[ind - 1])
continue;
625 const std::string base = logs.
path() +
"/" +
sn.nodes[ind - 1].name;
626 if (!detail::is_file(base +
"-Arv.csv") || !detail::is_file(base +
"-Dep.csv"))
continue;
629 std::vector<std::size_t> ca(arv.
cls.size(), 0), cd(dep.
cls.size(), 0);
630 for (std::size_t i = 0; i < arv.
cls.size(); ++i) {
631 const auto it = class_of.find(arv.
cls[i]);
632 ca[i] = it == class_of.end() ? 0 : it->second;
634 for (std::size_t i = 0; i < dep.
cls.size(); ++i) {
635 const auto it = class_of.find(dep.
cls[i]);
636 cd[i] = it == class_of.end() ? 0 : it->second;
638 const std::map<std::size_t, std::vector<double>> samples =
640 for (
const auto& kv : samples) {
641 if (kv.first == 0 || kv.second.empty())
continue;
642 std::vector<double> x = kv.second;
643 std::sort(x.begin(), x.end());
646 std::vector<std::pair<double, double>> fx;
647 fx.push_back(std::make_pair(0.0, x.front()));
649 while (i < x.size()) {
651 while (j + 1 < x.size() && x[j + 1] == x[i]) ++j;
652 fx.push_back(std::make_pair(
static_cast<double>(j + 1) /
653 static_cast<double>(x.size()),
657 out[std::make_pair(ist, kv.first)] = fx;
677 const JmtOptions&
opt, std::vector<std::vector<double>>& states_out) {
678 if (!std::isfinite(
opt.max_simulated_time))
680 "SolverJMT: getTranProbAggr requires a finite time span, e.g. "
681 "options.timespan = [0, T]");
682 if (station == 0 || station >
sn.nstations)
683 throw InputError(
"SolverJMT: getTranProbAggr was given a station index out of range");
684 const std::size_t ind =
sn.station_to_node[station - 1];
686 throw InputError(
"SolverJMT: getTranProbAggr does not apply to a Source");
688 std::vector<JmtSysTrace<T>> runs;
689 std::set<double> grid;
690 for (std::size_t it = 0; it < replications; ++it) {
692 o.
seed =
opt.seed +
static_cast<long>(it);
694 for (
double t :
tr.t) grid.insert(t);
697 std::vector<double> tu(grid.begin(), grid.end());
701 std::map<std::vector<double>, std::size_t> index;
702 std::vector<std::vector<double>> states;
703 std::vector<std::vector<std::size_t>> occupied(runs.size(),
704 std::vector<std::size_t>(tu.size(), 0));
705 for (std::size_t r = 0; r < runs.size(); ++r) {
706 const std::vector<std::vector<double>>& block = runs[r].state[station - 1];
707 if (block.
empty())
continue;
709 for (std::size_t g = 0; g < tu.size(); ++g) {
710 while (k + 1 < runs[r].t.size() && runs[r].t[k + 1] <= tu[g]) ++k;
711 if (k >= block.
size())
continue;
712 const std::vector<double>& s = block[k];
713 auto it = index.find(s);
714 if (it == index.end()) {
715 index[s] = states.size();
719 occupied[r][g] = it->second + 1;
722 std::vector<std::vector<double>> pi(tu.size(), std::vector<double>(states.size(), 0.0));
723 for (std::size_t r = 0; r < runs.size(); ++r)
724 for (std::size_t g = 0; g < tu.size(); ++g)
725 if (occupied[r][g] != 0)
726 pi[g][occupied[r][g] - 1] += 1.0 /
static_cast<double>(runs.size());
728 return std::make_pair(tu, pi);
741 std::vector<double> dt(t.size(), 0.0);
742 for (std::size_t i = 0; i + 1 < t.size(); ++i) dt[i] = t[i + 1] - t[i];
785 std::size_t target_station = 0,
786 const std::vector<double>& target = std::vector<double>()) {
788 if (!target.empty()) {
789 if (target_station == 0 || target_station >
sn.nstations)
790 throw InputError(
"SolverJMT: getProbAggr was given a station index out of range");
791 if (target.size() !=
sn.nclasses)
792 throw InputError(
"SolverJMT: getProbAggr takes one job count per class (" +
793 std::to_string(
sn.nclasses) +
"), got " +
794 std::to_string(target.size()));
795 for (std::size_t r = 0; r <
sn.nclasses; ++r)
798 std::vector<std::vector<double>> nir(
sn.nstations, std::vector<double>(
sn.nclasses, 0.0));
799 for (std::size_t i = 0; i <
sn.nstations; ++i)
800 for (std::size_t r = 0; r <
sn.nclasses; ++r)
809 std::vector<double> hit(
sn.nstations, 0.0);
810 double sys_hit = 0.0, total = 0.0;
811 for (std::size_t g = 0; g < dt.size(); ++g) {
814 for (std::size_t ist = 1; ist <=
sn.nstations; ++ist) {
815 const std::size_t ind =
sn.station_to_node[ist - 1];
819 const std::vector<std::vector<double>>& block =
tr.state[ist - 1];
820 bool same = g < block.
size();
821 for (std::size_t r = 0; r <
sn.nclasses && same; ++r)
822 same = block[g][r] == nir[ist - 1][r];
824 hit[ist - 1] += dt[g];
832 if (dt[g] > 0.0) out.
sys_seen =
true;
839 "SolverJMT: the simulation produced no observed dwell time, so no state probability "
840 "can be estimated from it");
841 out.
sys = sys_hit / total;
842 for (std::size_t i = 0; i <
sn.nstations; ++i) out.
station[i] = hit[i] / total;
849 std::vector<double>
t;
851 std::vector<std::vector<std::vector<double>>>
QNt;
852 std::vector<std::vector<std::vector<double>>>
UNt;
853 std::vector<std::vector<std::vector<double>>>
TNt;
883 if (!refusal.empty())
throw InputError(refusal);
885 const int reps =
opt.iter_max > 0 ?
opt.iter_max : 10;
887 std::vector<JmtSysTrace<T>> paths;
888 std::set<double> grid;
889 double tumax = std::numeric_limits<double>::infinity();
890 for (
int it = 0; it < reps; ++it) {
897 }
catch (
const std::exception&) {
900 if (
tr.t.empty())
continue;
901 tumax = std::min(tumax,
tr.t.back());
902 for (
double tv :
tr.t) grid.insert(tv);
907 "SolverJMT: no valid replications produced; the transient averages cannot be computed");
910 out.
valid = paths.size();
911 for (
double tv : grid)
912 if (tv <= tumax) out.
t.push_back(tv);
913 const std::size_t nt = out.
t.size();
914 const std::size_t M =
sn.nstations, K =
sn.nclasses;
915 out.
QNt.assign(M, std::vector<std::vector<double>>(K, std::vector<double>(nt, 0.0)));
916 out.
UNt.assign(M, std::vector<std::vector<double>>(K, std::vector<double>(nt, 0.0)));
917 out.
TNt.assign(M, std::vector<std::vector<double>>(K, std::vector<double>(nt, 0.0)));
919 const double inv = 1.0 /
static_cast<double>(paths.size());
920 for (std::size_t ist = 0; ist < M; ++ist) {
922 const bool finite_c = std::isfinite(c) && c > 0.0;
924 if (ist >=
tr.state.size() ||
tr.state[ist].empty())
continue;
925 const std::vector<std::vector<double>>& block =
tr.state[ist];
927 for (std::size_t g = 0; g < nt; ++g) {
928 while (k + 1 <
tr.t.size() &&
tr.t[k + 1] <= out.
t[g]) ++k;
929 if (out.
t[g] <
tr.t.front() || k >= block.
size())
continue;
930 for (std::size_t r = 0; r < K && r < block[k].
size(); ++r) {
931 const double n = block[k][r];
932 out.
QNt[ist][r][g] += inv * n;
933 out.
UNt[ist][r][g] += inv * (finite_c ? std::min(n, c) / c : n);
937 for (std::size_t r = 0; r < K; ++r) {
939 const double scale = std::isfinite(mu) ? (finite_c ? c * mu : mu) : 0.0;
940 for (std::size_t g = 0; g < nt; ++g) out.
TNt[ist][r][g] = out.
UNt[ist][r][g] * scale;
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.
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.
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::pair< std::vector< double >, std::vector< std::vector< double > > > jmt_get_tran_prob_aggr(const qn::NetworkStruct< T > &sn, std::size_t station, std::size_t replications, const JmtOptions &opt, std::vector< std::vector< double > > &states_out)
Port of getTranProbAggr: the transient distribution of one station's aggregate state,...
std::vector< double > jmt_dwell_weights(const std::vector< double > &t)
The dwell-time weights of a trajectory sampled at t.
JmtReplication< T > jmt_replication(const qn::NetworkStruct< T > &sn, const JmtOptions &opt)
Port of the replication method of @@SolverJMT/runAnalyzer.m.
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)
The structural half of SolverJMT's method gate; empty when admissible.
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.
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.
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>
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.