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 +
"'");
220inline bool document_postdates_native(
const std::string& doc) {
221 static const char* keys[] = {
"\"costCaps\"",
"\"classDependence\"",
222 "\"loadDependence\"",
"\"jointDependence\""};
223 for (std::size_t i = 0; i <
sizeof(keys) /
sizeof(keys[0]); ++i)
224 if (doc.find(keys[i]) != std::string::npos)
return true;
242 const std::vector<std::string>& extra) {
243 std::vector<std::string> f;
246 f.push_back(std::to_string(budget));
247 f.push_back(
"--seed");
248 f.push_back(std::to_string(o.
seed));
250 f.push_back(
"--method");
254 f.push_back(
"--cnvgon");
256 f.push_back(
"--cnvgtol");
257 f.push_back(detail::shortest(o.
cnvgtol));
260 f.push_back(
"--cnvgbatch");
261 f.push_back(std::to_string(o.
cnvgbatch));
264 f.push_back(
"--cnvgchk");
265 f.push_back(std::to_string(o.
cnvgchk));
269 f.push_back(
"--tranfilter");
273 f.push_back(
"--warmupfrac");
277 f.push_back(
"--tranobs");
278 f.push_back(std::to_string(o.
tranobs));
281 f.push_back(
"--mserbatch");
282 f.push_back(std::to_string(o.
mserbatch));
285 f.push_back(
"--cimethod");
289 f.push_back(
"--obmoverlap");
293 f.push_back(
"--ciminbatch");
297 f.push_back(
"--ciminobs");
298 f.push_back(std::to_string(o.
ciminobs));
301 f.push_back(
"--spectrallowfreqfrac");
307 f.push_back(
"--slotted");
309 f.push_back(
"--slotlength");
316 if ((o.
method ==
"parallel" || o.
method ==
"para") && reps <= 1) reps = 8;
318 f.push_back(
"--replications");
319 f.push_back(std::to_string(reps));
321 f.push_back(
"--numthreads");
326 f.push_back(
"--timespan");
327 f.push_back(detail::shortest(o.
t0) +
"," + detail::shortest(o.
t1));
330 f.push_back(
"--maxtime");
331 f.push_back(detail::shortest(o.
timeout));
334 f.push_back(
"--busyperiod");
341 f.push_back(
"--busyperiod-subnet");
347 for (std::size_t i = 0; i < o.
init_sol.size(); ++i)
348 v += (i ?
"," :
"") + detail::shortest(o.
init_sol[i]);
349 f.push_back(
"--initsol");
352 for (std::size_t i = 0; i < extra.size(); ++i) f.push_back(extra[i]);
371 const std::vector<std::string>& flags) {
373 std::vector<LdesRunner> out;
374 const std::string native = detail::native_ldes_path(dir);
375 if (!native.empty()) {
377 r.
argv.push_back(native);
378 r.
argv.push_back(
"solve");
382 const std::string java = detail::find_java();
383 const std::string jar = dir.empty() ? std::string() : dir +
"/ldes.jar";
384 if (!java.empty() && detail::is_file(jar)) {
386 r.
argv.push_back(java);
387 r.
argv.push_back(
"-jar");
388 r.
argv.push_back(jar);
389 r.
argv.push_back(
"solve");
394 if (out.size() > 1) {
398 bool prefer_jar = detail::document_postdates_native(doc);
399 for (std::size_t i = 0; i < flags.size() && !prefer_jar; ++i)
400 prefer_jar = flags[i] ==
"--respt-samples";
401 if (prefer_jar) std::swap(out[0], out[1]);
412inline detail::Json
ldes_solve_rest(
const std::string& base_url,
const std::string& doc,
413 const std::vector<std::string>& flags,
double timeout) {
414 std::string url = base_url;
415 while (!url.empty() && url[url.size() - 1] ==
'/') url.erase(url.size() - 1);
416 if (url.size() < 6 || url.compare(url.size() - 6, 6,
"/solve") != 0) url +=
"/api/v1/solve";
418 detail::Json payload = detail::Json::object();
419 detail::Json model = detail::Json::object();
420 model[
"content"] = doc;
421 model[
"base64"] =
false;
422 payload[
"model"] = model;
423 detail::Json fl = detail::Json::array();
424 for (std::size_t i = 0; i < flags.size(); ++i) fl.push_back(flags[i]);
425 payload[
"flags"] = fl;
427 const int millis = (timeout > 0.0 && std::isfinite(timeout))
428 ?
static_cast<int>((timeout + 30.0) * 1000.0)
431 if (resp.
body.empty())
432 throw NumericError(
"SolverLDES: the REST server at " + url +
" returned HTTP " +
433 std::to_string(resp.
status) +
" with no body");
434 detail::Json out = detail::Json::parse(resp.
body,
nullptr,
false);
435 if (out.is_discarded() || !out.is_object())
436 throw NumericError(
"SolverLDES: the REST server at " + url +
437 " returned a non-JSON body: " + resp.
body);
438 if (!out.contains(
"status") || out[
"status"].get<std::string>() !=
"ok") {
439 const std::string msg = out.contains(
"message") ? out[
"message"].get<std::string>()
440 : std::string(
"unspecified error");
441 const std::string err = out.contains(
"stderr") ? out[
"stderr"].get<std::string>()
443 throw NumericError(
"SolverLDES: the REST solve failed: " + msg +
444 (err.empty() ?
"" :
" (engine stderr: " + err +
")"));
446 return out[
"result"];
457 if (d.is_object() && d.contains(
"error"))
458 throw NumericError(
"SolverLDES: the engine reported an error: " +
459 d[
"error"].get<std::string>());
460 if (!d.is_object() || !d.contains(
"format") || d[
"format"].get<std::string>() !=
"ldes-result")
462 "SolverLDES: the engine wrote a document that is not an ldes-result; the run did not "
466 r.
method = d.contains(
"method") && !d[
"method"].is_null() ? d[
"method"].get<std::string>()
467 : std::string(
"default");
468 if (d.contains(
"runtime")) r.
runtime = d[
"runtime"].get<
double>();
469 if (d.contains(
"converged")) r.
converged = d[
"converged"].get<
bool>();
470 if (d.contains(
"stoppingReason") && !d[
"stoppingReason"].is_null())
473 if (d.contains(
"warnings") && d[
"warnings"].is_array())
474 for (
const auto& w : d[
"warnings"]) {
475 r.
warnings.push_back(w.get<std::string>());
476 std::fprintf(stderr,
"[SolverLDES] Warning: %s\n", r.
warnings.back().c_str());
478 if (d.contains(
"convergenceBatches")) r.
convergence_batches = d[
"convergenceBatches"].get<
long>();
479 if (d.contains(
"totalSimulatedEvents"))
482 const detail::Json& dim = detail::field(d,
"dimensions");
483 if (dim.is_object()) {
484 if (dim.contains(
"nstations")) r.
nstations = dim[
"nstations"].get<std::size_t>();
485 if (dim.contains(
"nclasses")) r.
nclasses = dim[
"nclasses"].get<std::size_t>();
486 if (dim.contains(
"nchains")) r.
nchains = dim[
"nchains"].get<std::size_t>();
487 if (dim.contains(
"stationNames"))
488 for (std::size_t i = 0; i < dim[
"stationNames"].size(); ++i)
489 r.
station_names.push_back(dim[
"stationNames"][i].get<std::string>());
490 if (dim.contains(
"classNames"))
491 for (std::size_t i = 0; i < dim[
"classNames"].size(); ++i)
492 r.
class_names.push_back(dim[
"classNames"][i].get<std::string>());
495 const detail::Json& m = detail::field(d,
"metrics");
496 r.
QN = detail::mat(detail::field(m,
"QN"));
497 r.
UN = detail::mat(detail::field(m,
"UN"));
498 r.
RN = detail::mat(detail::field(m,
"RN"));
499 r.
TN = detail::mat(detail::field(m,
"TN"));
500 r.
AN = detail::mat(detail::field(m,
"AN"));
501 r.
WN = detail::mat(detail::field(m,
"WN"));
502 r.
CN = detail::mat(detail::field(m,
"CN"));
503 r.
XN = detail::mat(detail::field(m,
"XN"));
504 r.
DropRateJoin = detail::mat(detail::field(m,
"DropRateJoin"));
506 const detail::Json& ci = detail::field(d,
"confidenceIntervals");
507 r.
QNCI = detail::mat(detail::field(ci,
"QNCI"));
508 r.
UNCI = detail::mat(detail::field(ci,
"UNCI"));
509 r.
RNCI = detail::mat(detail::field(ci,
"RNCI"));
510 r.
TNCI = detail::mat(detail::field(ci,
"TNCI"));
511 r.
ANCI = detail::mat(detail::field(ci,
"ANCI"));
512 r.
WNCI = detail::mat(detail::field(ci,
"WNCI"));
514 const detail::Json& rp = detail::field(d,
"relativePrecision");
515 r.
QNRelPrec = detail::mat(detail::field(rp,
"QNRelPrec"));
516 r.
UNRelPrec = detail::mat(detail::field(rp,
"UNRelPrec"));
517 r.
RNRelPrec = detail::mat(detail::field(rp,
"RNRelPrec"));
518 r.
TNRelPrec = detail::mat(detail::field(rp,
"TNRelPrec"));
520 const detail::Json& sc = detail::field(d,
"sampleCounts");
521 r.
QNSamples = detail::mat(detail::field(sc,
"QNSamples"));
522 r.
UNSamples = detail::mat(detail::field(sc,
"UNSamples"));
523 r.
RNSamples = detail::mat(detail::field(sc,
"RNSamples"));
524 r.
TNSamples = detail::mat(detail::field(sc,
"TNSamples"));
526 const detail::Json& fcr = detail::field(d,
"fcr");
527 if (fcr.is_object()) {
528 if (fcr.contains(
"nregions")) r.
nregions = fcr[
"nregions"].get<std::size_t>();
529 r.
QNfcr = detail::mat(detail::field(fcr,
"QNfcr"));
530 r.
UNfcr = detail::mat(detail::field(fcr,
"UNfcr"));
531 r.
RNfcr = detail::mat(detail::field(fcr,
"RNfcr"));
532 r.
TNfcr = detail::mat(detail::field(fcr,
"TNfcr"));
533 r.
ANfcr = detail::mat(detail::field(fcr,
"ANfcr"));
534 r.
WNfcr = detail::mat(detail::field(fcr,
"WNfcr"));
535 r.
WeightNfcr = detail::mat(detail::field(fcr,
"WeightNfcr"));
536 r.
MemOccNfcr = detail::mat(detail::field(fcr,
"MemOccNfcr"));
537 r.
DropRateNfcr = detail::mat(detail::field(fcr,
"DropRateNfcr"));
540 const detail::Json& imp = detail::field(d,
"impatience");
541 if (imp.is_object()) {
544 r.
renegingRate = detail::mat(detail::field(imp,
"renegingRate"));
545 r.
balkedCustomers = detail::mat(detail::field(imp,
"balkedCustomers"));
548 r.
retrialDropped = detail::mat(detail::field(imp,
"retrialDropped"));
549 r.
avgOrbitSize = detail::mat(detail::field(imp,
"avgOrbitSize"));
552 const detail::Json& cm = detail::field(d,
"cacheMetrics");
554 for (detail::Json::const_iterator it = cm.begin(); it != cm.end(); ++it) {
556 c.
hit = detail::mat(detail::field(it.value(),
"hit"));
557 c.
delayed = detail::mat(detail::field(it.value(),
"delayed"));
558 c.
miss = detail::mat(detail::field(it.value(),
"miss"));
559 c.
latency = detail::mat(detail::field(it.value(),
"latency"));
560 c.
hitList = detail::mat(detail::field(it.value(),
"hitList"));
561 c.
itemProb = detail::mat(detail::field(it.value(),
"itemProb"));
562 c.
listCost = detail::mat(detail::field(it.value(),
"listCost"));
566 const detail::Json& bp = detail::field(d,
"busyPeriods");
567 if (bp.is_object()) {
568 const detail::Json& targets = detail::field(bp,
"targets");
569 for (std::size_t i = 0; i < targets.size(); ++i) {
571 const detail::Json& tj = targets[i];
572 if (tj.contains(
"name") && tj[
"name"].is_string())
573 t.
name = tj[
"name"].get<std::string>();
574 const detail::Json& st = detail::field(tj,
"stations");
575 for (std::size_t k = 0; k < st.size(); ++k)
576 t.
stations.push_back(
static_cast<std::size_t
>(st[k].get<
double>()));
577 if (tj.contains(
"class") && tj[
"class"].is_number())
578 t.
job_class =
static_cast<int>(tj[
"class"].get<
double>());
579 t.
mean = detail::vec(detail::field(tj,
"mean"));
580 t.
count = detail::vec(detail::field(tj,
"count"));
585 const detail::Json& hist = detail::field(d,
"stateHistogram");
586 if (hist.is_object()) {
589 r.
traj_space = detail::mat(detail::field(hist,
"trajSpace"));
590 r.
traj_time = detail::mat(detail::field(hist,
"trajTime"));
596 const detail::Json& tran = detail::field(d,
"transient");
597 if (tran.is_object()) {
598 r.
t = detail::vec(detail::field(tran,
"t"));
599 const char* keys[3] = {
"QNt",
"UNt",
"TNt"};
600 std::vector<std::vector<Matrix<double>>>* dst[3] = {&r.
QNt, &r.
UNt, &r.
TNt};
601 for (
int q = 0; q < 3; ++q) {
602 const detail::Json& blk = detail::field(tran, keys[q]);
603 if (!blk.is_array())
continue;
604 for (std::size_t i = 0; i < blk.
size(); ++i) {
605 std::vector<Matrix<double>> row;
606 for (std::size_t k = 0; k < blk[i].
size(); ++k)
607 row.push_back(detail::mat(blk[i][k]));
608 dst[q]->push_back(row);
612 const detail::Json& rts = tran.is_object() && tran.contains(
"respTimeSamples")
613 ? tran[
"respTimeSamples"]
614 : detail::field(d,
"respTimeSamples");
616 for (std::size_t i = 0; i < rts.size(); ++i) {
617 std::vector<std::vector<double>> row;
618 for (std::size_t k = 0; k < rts[i].size(); ++k) row.push_back(detail::vec(rts[i][k]));
643 const std::vector<std::string>& extra_flags =
644 std::vector<std::string>()) {
645 const std::vector<std::string> flags =
ldes_flags(o, extra_flags);
647 const std::string model_path = tmp.
file(
"model.json");
648 const std::string result_path = tmp.
file(
"result.json");
650 detail::write_file(model_path, doc);
658 const std::vector<LdesRunner> runners =
ldes_runners(doc, flags);
663 ?
static_cast<int>(o.
timeout + 30.0)
665 std::string last_err;
666 for (std::size_t i = 0; i < runners.size(); ++i) {
667 std::vector<std::string> argv = runners[i].argv;
668 argv.push_back(model_path);
669 argv.push_back(
"-o");
670 argv.push_back(result_path);
671 for (std::size_t j = 0; j < flags.size(); ++j) argv.push_back(flags[j]);
672 std::remove(result_path.c_str());
675 for (std::size_t j = 0; j < argv.size(); ++j)
line += (j ?
" " :
"") + argv[j];
676 std::fprintf(stderr,
"SolverLDES command: %s\n",
line.c_str());
679 runners[i].
engine.c_str());
685 r.
engine = runners[i].engine;
688 if (p.
exitCode == 0 && detail::is_file(result_path)) {
690 const std::string text = detail::read_file(result_path);
691 detail::Json parsed = detail::Json::parse(text,
nullptr,
false);
692 if (parsed.is_discarded())
693 throw NumericError(
"SolverLDES: the engine wrote a result that is not JSON");
695 r.
engine = runners[i].engine;
700 throw NumericError(
"SolverLDES: the engine failed on all " +
701 std::to_string(runners.size()) +
" runner(s); " + last_err);
706 const std::vector<std::string>& extra_flags =
707 std::vector<std::string>()) {
751 const std::vector<LdesStateQuery>& query) {
754 "SolverLDES: this result carries no state histogram, so no state probability can be "
755 "read from it; the run has to pass --export-histogram");
757 throw InputError(
"SolverLDES: a state probability needs the model's class count");
760 for (std::size_t s = 0; s < nstates; ++s) total += r.
histogram_time(s, 0);
761 if (!(total > 0.0))
return 0.0;
764 for (std::size_t q = 0; q < query.size(); ++q) {
765 if (query[q].station == 0)
766 throw InputError(
"SolverLDES: a state query names station 0; stations are 1-based");
767 const std::size_t last = (query[q].station - 1) * nclasses + nclasses;
770 "SolverLDES: station " + std::to_string(query[q].station) +
771 " is past the end of the state histogram, which holds " + std::to_string(ncols) +
772 " columns for " + std::to_string(nclasses) +
" classes");
775 double matched = 0.0;
776 for (std::size_t s = 0; s < nstates; ++s) {
778 for (std::size_t q = 0; q < query.size() && ok; ++q) {
779 const std::size_t base = (query[q].station - 1) * nclasses;
780 const std::size_t n = std::min(nclasses, query[q].counts.size());
781 for (std::size_t k = 0; k < n; ++k)
782 if (std::fabs(r.
histogram_space(s, base + k) - query[q].counts[k]) > 1e-9) {
789 return matched / total;
812 std::size_t job_class) {
818 std::sort(x.begin(), x.end());
819 const std::size_t n = x.size();
820 std::vector<double> tu, fu;
821 for (std::size_t i = 0; i < n; ++i) {
822 const double f =
static_cast<double>(i + 1) /
static_cast<double>(n);
823 if (i + 1 < n && x[i + 1] == x[i])
continue;
828 for (std::size_t i = 0; i < tu.size(); ++i) {
850 const std::vector<double>& counts, std::size_t nclasses) {
851 std::vector<std::string> flags;
852 flags.push_back(
"--export-histogram");
854 std::vector<LdesStateQuery> q(1);
855 q[0].station = station;
856 q[0].counts = counts;
867 if (target.
rows() == 0 || target.
cols() == 0)
868 throw InputError(
"SolverLDES: getProbSysAggr needs an (nstations x nclasses) target state");
869 std::vector<std::string> flags;
870 flags.push_back(
"--export-histogram");
872 const std::size_t K = target.
cols();
873 std::vector<LdesStateQuery> q(target.
rows());
874 for (std::size_t i = 0; i < target.
rows(); ++i) {
875 q[i].station = i + 1;
876 q[i].counts.resize(K);
877 for (std::size_t k = 0; k < K; ++k) q[i].counts[k] = target(i, k);
895 const std::vector<std::string>& extra_flags =
896 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.
Conservation laws of a layered queueing network, enumerated from its structure.
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 tranobs
–tranobs, equally spaced transient observation points over [t0,t1]; fixes the time grid only.
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
std::vector< std::string > warnings
ldes-result "warnings": what the engine warned on its own console, e.g.
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.