5#ifndef LINE_SOLVERS_WRAPPERS_LDES_SOLVER_LDES_H
6#define LINE_SOLVERS_WRAPPERS_LDES_SOLVER_LDES_H
101#include <sys/utsname.h>
119using Json = nlohmann::json;
126inline std::string shortest(
double v) {
128 for (
int prec = 15; prec <= 17; ++prec) {
129 std::snprintf(buf,
sizeof(buf),
"%.*g", prec, v);
130 if (std::strtod(buf,
nullptr) == v)
return std::string(buf);
132 return std::string(buf);
136inline Matrix<double> mat(
const Json& v) {
137 if (v.is_null() || !v.is_array() || v.empty())
return Matrix<double>();
138 if (!v[0].is_array()) {
139 Matrix<double> m(1, v.size());
140 for (std::size_t j = 0; j < v.size(); ++j)
141 m(0, j) = v[j].is_null() ? std::numeric_limits<double>::quiet_NaN()
142 : v[j].
get<double>();
145 std::size_t cols = 0;
146 for (std::size_t i = 0; i < v.size(); ++i)
147 if (v[i].is_array() && v[i].size() > cols) cols = v[i].size();
148 Matrix<double> m(v.size(), cols, std::numeric_limits<double>::quiet_NaN());
149 for (std::size_t i = 0; i < v.size(); ++i) {
150 if (!v[i].is_array())
continue;
151 for (std::size_t j = 0; j < v[i].size(); ++j)
152 if (!v[i][j].is_null()) m(i, j) = v[i][j].get<
double>();
158inline std::vector<double> vec(
const Json& v) {
159 std::vector<double> out;
160 if (!v.is_array())
return out;
161 out.reserve(v.size());
162 for (std::size_t i = 0; i < v.size(); ++i)
163 out.push_back(v[i].is_null() ? std::numeric_limits<double>::quiet_NaN()
164 : v[i].get<
double>());
168inline const Json& field(
const Json& o,
const char* key) {
169 static const Json null_value;
170 return o.is_object() && o.contains(key) ? o[key] : null_value;
174inline std::string read_file(
const std::string& path) {
175 std::ifstream in(path.c_str(), std::ios::binary);
176 if (!in)
throw InputError(
"SolverLDES: cannot open the model document '" + path +
"'");
177 std::ostringstream ss;
182inline void write_file(
const std::string& path,
const std::string& text) {
183 std::ofstream out(path.c_str(), std::ios::binary);
184 if (!out)
throw InputError(
"SolverLDES: cannot write '" + path +
"'");
198inline bool document_postdates_native(
const std::string& doc) {
199 static const char* keys[] = {
"\"costCaps\"",
"\"markedClasses\"",
"\"classDependence\"",
200 "\"loadDependence\"",
"\"jointDependence\""};
201 for (std::size_t i = 0; i <
sizeof(keys) /
sizeof(keys[0]); ++i)
202 if (doc.find(keys[i]) != std::string::npos)
return true;
220 const std::vector<std::string>& extra) {
221 std::vector<std::string> f;
224 f.push_back(std::to_string(budget));
225 f.push_back(
"--seed");
226 f.push_back(std::to_string(o.
seed));
228 f.push_back(
"--method");
232 f.push_back(
"--cnvgon");
234 f.push_back(
"--cnvgtol");
235 f.push_back(detail::shortest(o.
cnvgtol));
238 f.push_back(
"--cnvgbatch");
239 f.push_back(std::to_string(o.
cnvgbatch));
242 f.push_back(
"--cnvgchk");
243 f.push_back(std::to_string(o.
cnvgchk));
247 f.push_back(
"--tranfilter");
251 f.push_back(
"--warmupfrac");
255 f.push_back(
"--mserbatch");
256 f.push_back(std::to_string(o.
mserbatch));
259 f.push_back(
"--cimethod");
263 f.push_back(
"--obmoverlap");
267 f.push_back(
"--ciminbatch");
271 f.push_back(
"--ciminobs");
272 f.push_back(std::to_string(o.
ciminobs));
275 f.push_back(
"--spectrallowfreqfrac");
281 f.push_back(
"--slotted");
283 f.push_back(
"--slotlength");
288 f.push_back(
"--replications");
291 f.push_back(
"--numthreads");
296 f.push_back(
"--timespan");
297 f.push_back(detail::shortest(o.
t0) +
"," + detail::shortest(o.
t1));
300 f.push_back(
"--maxtime");
301 f.push_back(detail::shortest(o.
timeout));
304 f.push_back(
"--busyperiod");
311 f.push_back(
"--busyperiod-subnet");
317 for (std::size_t i = 0; i < o.
init_sol.size(); ++i)
318 v += (i ?
"," :
"") + detail::shortest(o.
init_sol[i]);
319 f.push_back(
"--initsol");
322 for (std::size_t i = 0; i < extra.size(); ++i) f.push_back(extra[i]);
341 const std::vector<std::string>& flags) {
343 std::vector<LdesRunner> out;
344 const std::string native = detail::native_ldes_path(dir);
345 if (!native.empty()) {
347 r.
argv.push_back(native);
348 r.
argv.push_back(
"solve");
352 const std::string java = detail::find_java();
353 const std::string jar = dir.empty() ? std::string() : dir +
"/ldes.jar";
354 if (!java.empty() && detail::is_file(jar)) {
356 r.
argv.push_back(java);
357 r.
argv.push_back(
"-jar");
358 r.
argv.push_back(jar);
359 r.
argv.push_back(
"solve");
364 if (out.size() > 1) {
368 bool prefer_jar = detail::document_postdates_native(doc);
369 for (std::size_t i = 0; i < flags.size() && !prefer_jar; ++i)
370 prefer_jar = flags[i] ==
"--respt-samples";
371 if (prefer_jar) std::swap(out[0], out[1]);
382inline detail::Json
ldes_solve_rest(
const std::string& base_url,
const std::string& doc,
383 const std::vector<std::string>& flags,
double timeout) {
384 std::string url = base_url;
385 while (!url.empty() && url[url.size() - 1] ==
'/') url.erase(url.size() - 1);
386 if (url.size() < 6 || url.compare(url.size() - 6, 6,
"/solve") != 0) url +=
"/api/v1/solve";
388 detail::Json payload = detail::Json::object();
389 detail::Json model = detail::Json::object();
390 model[
"content"] = doc;
391 model[
"base64"] =
false;
392 payload[
"model"] = model;
393 detail::Json fl = detail::Json::array();
394 for (std::size_t i = 0; i < flags.size(); ++i) fl.push_back(flags[i]);
395 payload[
"flags"] = fl;
397 const int millis = (timeout > 0.0 && std::isfinite(timeout))
398 ?
static_cast<int>((timeout + 30.0) * 1000.0)
401 if (resp.
body.empty())
402 throw NumericError(
"SolverLDES: the REST server at " + url +
" returned HTTP " +
403 std::to_string(resp.
status) +
" with no body");
404 detail::Json out = detail::Json::parse(resp.
body,
nullptr,
false);
405 if (out.is_discarded() || !out.is_object())
406 throw NumericError(
"SolverLDES: the REST server at " + url +
407 " returned a non-JSON body: " + resp.
body);
408 if (!out.contains(
"status") || out[
"status"].get<std::string>() !=
"ok") {
409 const std::string msg = out.contains(
"message") ? out[
"message"].get<std::string>()
410 : std::string(
"unspecified error");
411 const std::string err = out.contains(
"stderr") ? out[
"stderr"].get<std::string>()
413 throw NumericError(
"SolverLDES: the REST solve failed: " + msg +
414 (err.empty() ?
"" :
" (engine stderr: " + err +
")"));
416 return out[
"result"];
427 if (d.is_object() && d.contains(
"error"))
428 throw NumericError(
"SolverLDES: the engine reported an error: " +
429 d[
"error"].get<std::string>());
430 if (!d.is_object() || !d.contains(
"format") || d[
"format"].get<std::string>() !=
"ldes-result")
432 "SolverLDES: the engine wrote a document that is not an ldes-result; the run did not "
436 r.
method = d.contains(
"method") && !d[
"method"].is_null() ? d[
"method"].get<std::string>()
437 : std::string(
"default");
438 if (d.contains(
"runtime")) r.
runtime = d[
"runtime"].get<
double>();
439 if (d.contains(
"converged")) r.
converged = d[
"converged"].get<
bool>();
440 if (d.contains(
"stoppingReason") && !d[
"stoppingReason"].is_null())
442 if (d.contains(
"convergenceBatches")) r.
convergence_batches = d[
"convergenceBatches"].get<
long>();
443 if (d.contains(
"totalSimulatedEvents"))
446 const detail::Json& dim = detail::field(d,
"dimensions");
447 if (dim.is_object()) {
448 if (dim.contains(
"nstations")) r.
nstations = dim[
"nstations"].get<std::size_t>();
449 if (dim.contains(
"nclasses")) r.
nclasses = dim[
"nclasses"].get<std::size_t>();
450 if (dim.contains(
"nchains")) r.
nchains = dim[
"nchains"].get<std::size_t>();
451 if (dim.contains(
"stationNames"))
452 for (std::size_t i = 0; i < dim[
"stationNames"].size(); ++i)
453 r.
station_names.push_back(dim[
"stationNames"][i].get<std::string>());
454 if (dim.contains(
"classNames"))
455 for (std::size_t i = 0; i < dim[
"classNames"].size(); ++i)
456 r.
class_names.push_back(dim[
"classNames"][i].get<std::string>());
459 const detail::Json& m = detail::field(d,
"metrics");
460 r.
QN = detail::mat(detail::field(m,
"QN"));
461 r.
UN = detail::mat(detail::field(m,
"UN"));
462 r.
RN = detail::mat(detail::field(m,
"RN"));
463 r.
TN = detail::mat(detail::field(m,
"TN"));
464 r.
AN = detail::mat(detail::field(m,
"AN"));
465 r.
WN = detail::mat(detail::field(m,
"WN"));
466 r.
CN = detail::mat(detail::field(m,
"CN"));
467 r.
XN = detail::mat(detail::field(m,
"XN"));
468 r.
DropRateJoin = detail::mat(detail::field(m,
"DropRateJoin"));
470 const detail::Json& ci = detail::field(d,
"confidenceIntervals");
471 r.
QNCI = detail::mat(detail::field(ci,
"QNCI"));
472 r.
UNCI = detail::mat(detail::field(ci,
"UNCI"));
473 r.
RNCI = detail::mat(detail::field(ci,
"RNCI"));
474 r.
TNCI = detail::mat(detail::field(ci,
"TNCI"));
475 r.
ANCI = detail::mat(detail::field(ci,
"ANCI"));
476 r.
WNCI = detail::mat(detail::field(ci,
"WNCI"));
478 const detail::Json& rp = detail::field(d,
"relativePrecision");
479 r.
QNRelPrec = detail::mat(detail::field(rp,
"QNRelPrec"));
480 r.
UNRelPrec = detail::mat(detail::field(rp,
"UNRelPrec"));
481 r.
RNRelPrec = detail::mat(detail::field(rp,
"RNRelPrec"));
482 r.
TNRelPrec = detail::mat(detail::field(rp,
"TNRelPrec"));
484 const detail::Json& sc = detail::field(d,
"sampleCounts");
485 r.
QNSamples = detail::mat(detail::field(sc,
"QNSamples"));
486 r.
UNSamples = detail::mat(detail::field(sc,
"UNSamples"));
487 r.
RNSamples = detail::mat(detail::field(sc,
"RNSamples"));
488 r.
TNSamples = detail::mat(detail::field(sc,
"TNSamples"));
490 const detail::Json& fcr = detail::field(d,
"fcr");
491 if (fcr.is_object()) {
492 if (fcr.contains(
"nregions")) r.
nregions = fcr[
"nregions"].get<std::size_t>();
493 r.
QNfcr = detail::mat(detail::field(fcr,
"QNfcr"));
494 r.
UNfcr = detail::mat(detail::field(fcr,
"UNfcr"));
495 r.
RNfcr = detail::mat(detail::field(fcr,
"RNfcr"));
496 r.
TNfcr = detail::mat(detail::field(fcr,
"TNfcr"));
497 r.
ANfcr = detail::mat(detail::field(fcr,
"ANfcr"));
498 r.
WNfcr = detail::mat(detail::field(fcr,
"WNfcr"));
499 r.
WeightNfcr = detail::mat(detail::field(fcr,
"WeightNfcr"));
500 r.
MemOccNfcr = detail::mat(detail::field(fcr,
"MemOccNfcr"));
501 r.
DropRateNfcr = detail::mat(detail::field(fcr,
"DropRateNfcr"));
504 const detail::Json& imp = detail::field(d,
"impatience");
505 if (imp.is_object()) {
508 r.
renegingRate = detail::mat(detail::field(imp,
"renegingRate"));
509 r.
balkedCustomers = detail::mat(detail::field(imp,
"balkedCustomers"));
512 r.
retrialDropped = detail::mat(detail::field(imp,
"retrialDropped"));
513 r.
avgOrbitSize = detail::mat(detail::field(imp,
"avgOrbitSize"));
516 const detail::Json& cm = detail::field(d,
"cacheMetrics");
518 for (detail::Json::const_iterator it = cm.begin(); it != cm.end(); ++it) {
520 c.
hit = detail::mat(detail::field(it.value(),
"hit"));
521 c.
delayed = detail::mat(detail::field(it.value(),
"delayed"));
522 c.
miss = detail::mat(detail::field(it.value(),
"miss"));
523 c.
latency = detail::mat(detail::field(it.value(),
"latency"));
524 c.
hitList = detail::mat(detail::field(it.value(),
"hitList"));
525 c.
itemProb = detail::mat(detail::field(it.value(),
"itemProb"));
526 c.
listCost = detail::mat(detail::field(it.value(),
"listCost"));
530 const detail::Json& bp = detail::field(d,
"busyPeriods");
531 if (bp.is_object()) {
532 const detail::Json& targets = detail::field(bp,
"targets");
533 for (std::size_t i = 0; i < targets.size(); ++i) {
535 const detail::Json& tj = targets[i];
536 if (tj.contains(
"name") && tj[
"name"].is_string())
537 t.
name = tj[
"name"].get<std::string>();
538 const detail::Json& st = detail::field(tj,
"stations");
539 for (std::size_t k = 0; k < st.size(); ++k)
540 t.
stations.push_back(
static_cast<std::size_t
>(st[k].get<
double>()));
541 if (tj.contains(
"class") && tj[
"class"].is_number())
542 t.
job_class =
static_cast<int>(tj[
"class"].get<
double>());
543 t.
mean = detail::vec(detail::field(tj,
"mean"));
544 t.
count = detail::vec(detail::field(tj,
"count"));
549 const detail::Json& hist = detail::field(d,
"stateHistogram");
550 if (hist.is_object()) {
553 r.
traj_space = detail::mat(detail::field(hist,
"trajSpace"));
554 r.
traj_time = detail::mat(detail::field(hist,
"trajTime"));
560 const detail::Json& tran = detail::field(d,
"transient");
561 if (tran.is_object()) {
562 r.
t = detail::vec(detail::field(tran,
"t"));
563 const char* keys[3] = {
"QNt",
"UNt",
"TNt"};
564 std::vector<std::vector<Matrix<double>>>* dst[3] = {&r.
QNt, &r.
UNt, &r.
TNt};
565 for (
int q = 0; q < 3; ++q) {
566 const detail::Json& blk = detail::field(tran, keys[q]);
567 if (!blk.is_array())
continue;
568 for (std::size_t i = 0; i < blk.
size(); ++i) {
569 std::vector<Matrix<double>> row;
570 for (std::size_t k = 0; k < blk[i].
size(); ++k)
571 row.push_back(detail::mat(blk[i][k]));
572 dst[q]->push_back(row);
576 const detail::Json& rts = tran.is_object() && tran.contains(
"respTimeSamples")
577 ? tran[
"respTimeSamples"]
578 : detail::field(d,
"respTimeSamples");
580 for (std::size_t i = 0; i < rts.size(); ++i) {
581 std::vector<std::vector<double>> row;
582 for (std::size_t k = 0; k < rts[i].size(); ++k) row.push_back(detail::vec(rts[i][k]));
607 const std::vector<std::string>& extra_flags =
608 std::vector<std::string>()) {
609 const std::vector<std::string> flags =
ldes_flags(o, extra_flags);
611 const std::string model_path = tmp.
file(
"model.json");
612 const std::string result_path = tmp.
file(
"result.json");
614 detail::write_file(model_path, doc);
622 const std::vector<LdesRunner> runners =
ldes_runners(doc, flags);
627 ?
static_cast<int>(o.
timeout + 30.0)
629 std::string last_err;
630 for (std::size_t i = 0; i < runners.size(); ++i) {
631 std::vector<std::string> argv = runners[i].argv;
632 argv.push_back(model_path);
633 argv.push_back(
"-o");
634 argv.push_back(result_path);
635 for (std::size_t j = 0; j < flags.size(); ++j) argv.push_back(flags[j]);
636 std::remove(result_path.c_str());
639 for (std::size_t j = 0; j < argv.size(); ++j)
line += (j ?
" " :
"") + argv[j];
640 std::fprintf(stderr,
"SolverLDES command: %s\n",
line.c_str());
643 runners[i].
engine.c_str());
649 r.
engine = runners[i].engine;
652 if (p.
exitCode == 0 && detail::is_file(result_path)) {
654 const std::string text = detail::read_file(result_path);
655 detail::Json parsed = detail::Json::parse(text,
nullptr,
false);
656 if (parsed.is_discarded())
657 throw NumericError(
"SolverLDES: the engine wrote a result that is not JSON");
659 r.
engine = runners[i].engine;
664 throw NumericError(
"SolverLDES: the engine failed on all " +
665 std::to_string(runners.size()) +
" runner(s); " + last_err);
670 const std::vector<std::string>& extra_flags =
671 std::vector<std::string>()) {
715 const std::vector<LdesStateQuery>& query) {
718 "SolverLDES: this result carries no state histogram, so no state probability can be "
719 "read from it; the run has to pass --export-histogram");
721 throw InputError(
"SolverLDES: a state probability needs the model's class count");
724 for (std::size_t s = 0; s < nstates; ++s) total += r.
histogram_time(s, 0);
725 if (!(total > 0.0))
return 0.0;
728 for (std::size_t q = 0; q < query.size(); ++q) {
729 if (query[q].station == 0)
730 throw InputError(
"SolverLDES: a state query names station 0; stations are 1-based");
731 const std::size_t last = (query[q].station - 1) * nclasses + nclasses;
734 "SolverLDES: station " + std::to_string(query[q].station) +
735 " is past the end of the state histogram, which holds " + std::to_string(ncols) +
736 " columns for " + std::to_string(nclasses) +
" classes");
739 double matched = 0.0;
740 for (std::size_t s = 0; s < nstates; ++s) {
742 for (std::size_t q = 0; q < query.size() && ok; ++q) {
743 const std::size_t base = (query[q].station - 1) * nclasses;
744 const std::size_t n = std::min(nclasses, query[q].counts.size());
745 for (std::size_t k = 0; k < n; ++k)
746 if (std::fabs(r.
histogram_space(s, base + k) - query[q].counts[k]) > 1e-9) {
753 return matched / total;
776 std::size_t job_class) {
782 std::sort(x.begin(), x.end());
783 const std::size_t n = x.size();
784 std::vector<double> tu, fu;
785 for (std::size_t i = 0; i < n; ++i) {
786 const double f =
static_cast<double>(i + 1) /
static_cast<double>(n);
787 if (i + 1 < n && x[i + 1] == x[i])
continue;
792 for (std::size_t i = 0; i < tu.size(); ++i) {
814 const std::vector<double>& counts, std::size_t nclasses) {
815 std::vector<std::string> flags;
816 flags.push_back(
"--export-histogram");
818 std::vector<LdesStateQuery> q(1);
819 q[0].station = station;
820 q[0].counts = counts;
831 if (target.
rows() == 0 || target.
cols() == 0)
832 throw InputError(
"SolverLDES: getProbSysAggr needs an (nstations x nclasses) target state");
833 std::vector<std::string> flags;
834 flags.push_back(
"--export-histogram");
836 const std::size_t K = target.
cols();
837 std::vector<LdesStateQuery> q(target.
rows());
838 for (std::size_t i = 0; i < target.
rows(); ++i) {
839 q[i].station = i + 1;
840 q[i].counts.resize(K);
841 for (std::size_t k = 0; k < K; ++k) q[i].counts[k] = target(i, k);
859 const std::vector<std::string>& extra_flags =
860 std::vector<std::string>()) {
NumericError(const std::string &what)
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
static void step(const char *fmt,...)
Write one progress line.
std::string file(const std::string &name) const
A file inside it.
The exception types the port throws.
Minimal HTTP/1.1 client, enough to talk to a line-*-rest service.
The option and result records of SolverLDES, the discrete-event simulator.
Where the LDES engine is, and whether this machine can run it.
Running progress log of a LINE solver run (the "solver console").
Dense matrix and non-owning view.
Response post_json(const std::string &url, const std::string &json, int timeoutMillis)
POST a JSON document.
Response get(const std::string &url, int timeoutMillis)
GET a URL.
detail::json network_json_envelope(const qn::NetworkStruct< T > &sn)
The complete model.json envelope: {format, version, model}.
double ldes_prob_from_histogram(const LdesResult &r, std::size_t nclasses, const std::vector< LdesStateQuery > &query)
Residence-time probability of an aggregate joint state, from a parsed result.
LdesResult solver_ldes_text(const std::string &doc, const LdesOptions &o, const std::vector< std::string > &extra_flags=std::vector< std::string >())
Runs one LDES simulation on a model.json DOCUMENT and parses its result.
double ldes_prob_sys_aggr(const std::string &doc, const LdesOptions &o, const Matrix< double > &target)
Port of getProbSysAggr: the joint probability of a whole aggregate state.
LdesResult solver_ldes_file(const std::string &path, const LdesOptions &o, const std::vector< std::string > &extra_flags=std::vector< std::string >())
The same, reading the document from a file.
const std::string & ldes_engine_dir()
The directory holding the engine, or empty when there is none.
std::vector< std::string > ldes_flags(const LdesOptions &o, const std::vector< std::string > &extra)
The engine flags of one run, after solve <model> -o <result>.
Matrix< double > ldes_cdf_respt(const LdesResult &r, std::size_t station, std::size_t job_class)
Port of getCdfRespT: the EMPIRICAL response time CDF of one (station, class) pair,...
LdesResult parse_ldes_result(const detail::Json &d)
Parses one ldes-result document.
double ldes_prob_aggr(const std::string &doc, const LdesOptions &o, std::size_t station, const std::vector< double > &counts, std::size_t nclasses)
Port of getProbAggr: the marginal probability of a per-class job count at one station.
detail::Json ldes_solve_rest(const std::string &base_url, const std::string &doc, const std::vector< std::string > &flags, double timeout)
Solves through an LDES REST server and returns its result document.
LdesResult solver_ldes(const qn::NetworkStruct< T > &sn, const LdesOptions &o, const std::vector< std::string > &extra_flags=std::vector< std::string >())
The same, for a model built through the C++ API.
std::vector< LdesRunner > ldes_runners(const std::string &doc, const std::vector< std::string > &flags)
The runners to try, in order (see the file header for why there are two and when the order flips).
ProcResult capture(const std::vector< std::string > &argv, int timeoutSeconds, bool mergeStderr=false)
Runs a command, capturing stdout and discarding stderr.
std::string trim(const std::string &s)
Trims ASCII whitespace from both ends, as Java's String.trim() does.
qn::NetworkStruct -> model.json, the inverse of network_reader.h.
An HTTP response, with the body already de-chunked.
std::string body
Response body, decoded.
int status
HTTP status code.
Per-cache hit/miss/latency, as the cacheMetrics block carries them.
Matrix< double > listCost
(1 x nlists) mean storage cost held per list
Matrix< double > latency
(1 x nclasses) expected retrieval latency
Matrix< double > hitList
(nclasses x nlists) hit probability by list
Matrix< double > itemProb
(nitems x nlists+1) item position law
Matrix< double > delayed
(1 x nclasses) delayed-hit probability
Matrix< double > miss
(1 x nclasses) miss probability
Matrix< double > hit
(1 x nclasses) hit probability
The knobs of one LDES run.
double warmupfrac
–warmupfrac, only for tranfilter=fixed
int ciminbatch
–ciminbatch
double spectral_low_freq_frac
–spectrallowfreqfrac
bool verbose
echo the resolved command line before running it
std::string rest_url
Base URL of an LDES REST server (the imperialqore/ldes container).
double obmoverlap
–obmoverlap; 0 reduces OBM to plain batch means
std::vector< std::vector< std::size_t > > busy_period_subnets
–busyperiod-subnet, zero-based station indexes, one flag per set.
long seed
–seed; -1 requests a random stream
bool slotted
–slotted, run on the slot lattice
int mserbatch
–mserbatch, MSER batch size
std::string cimethod
–cimethod: obm | bm | spectral | none
double slot_length
–slotlength
int cnvgchk
–cnvgchk, events between checks; 0 = samples/50
int replications
–replications; 0 = not given (one path)
int ciminobs
–ciminobs, below which no CI is reported
std::size_t events
0 = not given; overrides samples when set
int cnvgbatch
–cnvgbatch, batches before the first check
std::string tranfilter
–tranfilter: mser5 | fixed | none
std::vector< double > init_sol
–initsol, the warm-start placement as a STATION-MAJOR vector [st0_cl0, st0_cl1, .....
int numthreads
–numthreads; 0 = not given
std::size_t samples
-s, service-completion budget
double timeout
–maxtime, a COOPERATIVE wall-clock budget the event loop polls.
bool has_timespan
true when [t0,t1] was set: a TRANSIENT run
int busy_period_orders
–busyperiod: highest busy period order measured, 0 disabling the measurement.
One measured busy period target (–busyperiod): a station, a station-class pair, or a declared station...
std::vector< std::size_t > stations
station indexes, zero-based
std::vector< double > mean
std::vector< double > count
One ldes-result document, parsed.
Matrix< double > balkedCustomers
Matrix< double > QNSamples
std::map< std::string, LdesCacheMetrics > cache_metrics
Per-cache metrics, keyed by the Cache NODE name.
Matrix< double > avgOrbitSize
Matrix< double > QNRelPrec
std::vector< std::vector< Matrix< double > > > QNt
[STATION][class] -> (npoints x 2), columns [value, time].
Matrix< double > renegingRate
Matrix< double > XN
(1 x nclasses), per-class visits and system tput
std::vector< std::vector< std::vector< double > > > respTimeSamples
[station][class] -> the per-job response times the engine recorded.
Matrix< double > WeightNfcr
Matrix< double > RNRelPrec
Matrix< double > avgRenegingWaitTime
Matrix< double > traj_space
Matrix< double > DropRateNfcr
Matrix< double > histogram_space
The exact joint-state residence-time histogram (–export-histogram).
std::string stopping_reason
convergence | max_events | max_sim_events | max_time.
std::vector< std::vector< Matrix< double > > > UNt
std::vector< std::string > class_names
Matrix< double > TNRelPrec
Matrix< double > TNSamples
Matrix< double > UNRelPrec
std::string engine
"native" or "jar": which runner produced these numbers.
Matrix< double > traj_time
std::vector< BusyPeriodTarget > busy_periods
Matrix< double > retriedCustomers
Matrix< double > retrialDropped
long long total_simulated_events
Matrix< double > MemOccNfcr
std::vector< std::string > station_names
Matrix< double > DropRateJoin
quorum-Join sibling drops, Join rows only
Matrix< double > UNSamples
bool timed_out
True when the HARD subprocess bound fired, not the cooperative one.
Matrix< double > balkingProbability
Matrix< double > renegedCustomers
Matrix< double > histogram_time
Matrix< double > RNSamples
std::vector< double > t
the time vector, empty on a steady-state run
std::vector< std::vector< Matrix< double > > > TNt
One runner: the argv prefix that runs the engine, and the name of its image.
std::vector< std::string > argv
up to and including "solve"
std::string engine
"native" or "jar"
One constraint of a joint-state query: a station and the per-class job counts it is required to hold.
std::vector< double > counts
Outcome of a captured command.
int exitCode
Exit status, or -1 when the command could not run.
bool timedOut
True when the deadline expired and the child was killed.
std::string out
Everything the command wrote to stdout.
Running an external command and capturing its output, with a deadline.
A scratch directory for the subprocess wrappers, the port's lineTempName.