56 const std::string& jobclass)
const {
57 for (std::size_t i = 0; i <
Station.size(); ++i) {
59 if (col ==
"QLen")
return QLen[i];
60 if (col ==
"Util")
return Util[i];
61 if (col ==
"RespT")
return RespT[i];
62 if (col ==
"ResidT")
return ResidT[i];
63 if (col ==
"ArvR")
return ArvR[i];
64 if (col ==
"Tput")
return Tput[i];
65 throw InputError(
"AvgTable::get: unknown column '" + col +
"'");
67 return std::numeric_limits<double>::quiet_NaN();
71 if (col ==
"QLen")
return QLen;
72 if (col ==
"Util")
return Util;
73 if (col ==
"RespT")
return RespT;
74 if (col ==
"ResidT")
return ResidT;
75 if (col ==
"ArvR")
return ArvR;
76 if (col ==
"Tput")
return Tput;
77 throw InputError(
"AvgTable::column: unknown column '" + col +
"'");
84 for (std::size_t i = 0; i <
sn.nstations; ++i)
85 for (std::size_t c = 0; c <
sn.nclasses; ++c) {
86 const double q = r.
QN(i, c), u = r.
UN(i, c), rt = r.
RN(i, c);
87 const double w = r.
WN(i, c), a = r.
AN(i, c), x = r.
TN(i, c);
88 if (q == 0.0 && u == 0.0 && rt == 0.0 && w == 0.0 && a == 0.0 && x == 0.0)
continue;
93 t.
RespT.push_back(rt);
98 for (std::size_t c = 0; c < sn.
nclasses && c < r.
CN.size(); ++c) {
101 t.
SysTput.push_back(c < r.
XN.size() ? r.
XN[c] : 0.0);
126 const std::size_t M =
sn.nstations, K =
sn.nclasses;
128 for (std::size_t i = 0; i < M; ++i)
129 for (std::size_t c = 0; c < K; ++c) {
130 RN(i, c) = r.RN(i, c);
131 TN(i, c) = r.TN(i, c);
135 for (std::size_t i = 0; i < M; ++i)
136 for (std::size_t c = 0; c < K; ++c) {
137 const double q = r.QN(i, c), u = r.UN(i, c), rt = r.RN(i, c), x = r.TN(i, c);
139 const double w = WN(i, c), a = is_source ? 0.0 : AN(i, c);
142 if (q == 0.0 && u == 0.0 && rt == 0.0 && w == 0.0 && a == 0.0 && x == 0.0)
continue;
143 t.Station.push_back(
sn.stations[i].name);
144 t.JobClass.push_back(
sn.classes[c].name);
147 t.RespT.push_back(rt);
148 t.ResidT.push_back(w);
152 for (std::size_t c = 0; c <
sn.nclasses && c < r.CN.size(); ++c) {
153 t.SysClass.push_back(
sn.classes[c].name);
154 t.SysRespT.push_back(r.CN[c]);
155 t.SysTput.push_back(c < r.XN.size() ? r.XN[c] : 0.0);
172 for (std::size_t i = 0; i <
sn.nstations; ++i)
173 for (std::size_t c = 0; c <
sn.nclasses; ++c) {
174 const double q = r.QN(i, c), u = r.UN(i, c), rt = r.RN(i, c);
175 const double w = WNfix(i, c), a = r.AN(i, c), x = r.TN(i, c);
176 if (q == 0.0 && u == 0.0 && rt == 0.0 && w == 0.0 && a == 0.0 && x == 0.0)
continue;
177 t.Station.push_back(
sn.stations[i].name);
178 t.JobClass.push_back(
sn.classes[c].name);
181 t.RespT.push_back(rt);
182 t.ResidT.push_back(w);
186 for (std::size_t c = 0; c <
sn.nclasses && c < r.CN.cols(); ++c) {
187 t.SysClass.push_back(
sn.classes[c].name);
188 t.SysRespT.push_back(r.CN(0, c));
189 t.SysTput.push_back(c < r.XN.cols() ? r.XN(0, c) : 0.0);
195 if (!o.method.empty()) c.
method = o.method;
196 if (o.cutoff > 0.0) c.cutoff = o.cutoff;
197 if (!o.cutoff_vec.empty()) c.cutoff_vec = o.cutoff_vec;
198 if (o.state_max) c.state_max = o.state_max;
204 if (!o.method.empty()) f.
method = o.method;
205 if (o.tol >= 0.0) f.tol = o.tol;
206 if (o.iter_tol >= 0.0) f.iter_tol = o.iter_tol;
207 if (o.iter_max >= 0) f.iter_max =
static_cast<std::size_t
>(o.iter_max);
208 if (o.timespan_end > 0.0) f.timespan_end = o.timespan_end;
209 if (!o.init_sol.empty()) f.init_sol = o.init_sol;
210 if (o.seed) f.seed = o.seed;
211 if (!o.highvar.empty()) f.highvar = o.highvar;
218 if (name !=
"AUTO")
return name;
220 std::transform(picked.begin(), picked.end(), picked.begin(), ::toupper);
221 if (picked ==
"FLUID") picked =
"FLD";
240 "' analyses a LayeredNetwork rather than a Network");
242 const std::string name = resolve_auto(
name_,
sn);
257 fill_table(t,
sn, r);
258 }
else if (name ==
"NC") {
271 fill_table(t,
sn, r);
272 }
else if (name ==
"CTMC") {
276 fill_table(t,
sn, r);
277 }
else if (name ==
"MAM") {
284 fill_table(t,
sn, r);
285 }
else if (name ==
"BA") {
291 fill_table(t,
sn, r);
292 }
else if (name ==
"SSA") {
301 fill_table_sim(t,
sn, r);
302 }
else if (name ==
"FLD" || name ==
"FLUID") {
307 fill_table_sim(t,
sn, r);
308 }
else if (name ==
"JMT") {
317 fill_table(t,
sn, r.
avg);
318 }
else if (name ==
"LDES") {
326 fill_table_ldes(t,
sn, r);
371 opt.keep_filtration =
true;
380 const std::size_t ist =
sn.nodes[node - 1].station;
381 if (ist == 0)
throw InputError(
"prob_aggr: the node is not a station");
382 const std::size_t K =
sn.nclasses;
383 if (state.size() != K)
throw InputError(
"prob_aggr: the state must have one entry per class");
385 for (std::size_t s = 0; s < A.
rows(); ++s) {
387 for (std::size_t k = 0; k < K && hit; ++k) hit = A(s, (ist - 1) * K + k) == state[k];
388 if (hit) p += d.
pi[s];
397 const std::size_t ist =
sn.nodes[node - 1].station;
398 if (ist == 0)
throw InputError(
"marg_aggr: the node is not a station");
399 const std::size_t K =
sn.nclasses;
400 std::size_t nmax = 0;
401 for (std::size_t s = 0; s < A.
rows(); ++s) {
403 for (std::size_t k = 0; k < K; ++k) tot += A(s, (ist - 1) * K + k);
404 nmax = std::max(nmax,
static_cast<std::size_t
>(tot));
406 std::vector<double> pmf(nmax + 1, 0.0);
407 for (std::size_t s = 0; s < A.
rows(); ++s) {
409 for (std::size_t k = 0; k < K; ++k) tot += A(s, (ist - 1) * K + k);
410 pmf[
static_cast<std::size_t
>(tot)] += d.
pi[s];
417 std::vector<std::vector<CdfCurve> > out(
sn.nstations, std::vector<CdfCurve>(
sn.nclasses));
418 const std::vector<std::vector<ctmc::CdfCurve<double> > > R =
420 for (std::size_t i = 0; i < R.size() && i < out.size(); ++i)
421 for (std::size_t c = 0; c < R[i].size() && c < out[i].size(); ++c) {
422 out[i][c].t = R[i][c].t;
423 out[i][c].F = R[i][c].F;
429 std::printf(
"%8s %-28s %s\n",
"State",
"Marking",
"Rates (to: rate)");
430 for (std::size_t i = 0; i < Q.
rows(); ++i) {
432 if (i < space.
rows()) {
433 std::ostringstream os;
435 for (std::size_t c = 0; c < space.
cols(); ++c) os << (c ?
" " :
"") << space(i, c);
439 std::printf(
"%8zu %-28s", i + 1, mark.c_str());
440 for (std::size_t j = 0; j < Q.
cols(); ++j)
441 if (i != j && Q(i, j) != 0.0) std::printf(
" %zu: %.6g", j + 1, Q(i, j));
452 const std::vector<fluid::FluidTranPoint> pts =
455 for (std::size_t i = 0; i <
sn.nstations; ++i)
456 for (std::size_t c = 0; c <
sn.nclasses; ++c)
457 out.
label.push_back(
sn.stations[i].name +
"/" +
sn.classes[c].name);
458 for (std::size_t s = 0; s < pts.size(); ++s) {
459 out.
t.push_back(pts[s].t);
460 std::vector<double> row;
461 for (std::size_t i = 0; i <
sn.nstations; ++i)
462 for (std::size_t c = 0; c <
sn.nclasses; ++c) row.push_back(pts[s].QN(i, c));
463 out.
QNt.push_back(row);
470 std::vector<std::vector<CdfCurve> > out(
sn.nstations, std::vector<CdfCurve>(
sn.nclasses));
471 const std::vector<std::vector<fluid::FluidPassage> > R =
473 for (std::size_t i = 0; i < R.size() && i < out.size(); ++i)
474 for (std::size_t c = 0; c < R[i].size() && c < out[i].size(); ++c) {
475 out[i][c].t = R[i][c].t;
476 out[i][c].F = R[i][c].cdf;
493 for (std::size_t i = 0; i <
sn.nstations; ++i)
494 for (std::size_t c = 0; c <
sn.nclasses; ++c) {
495 if (i < b.
keep.size() && c < b.
keep[i].size() && !b.
keep[i][c])
continue;
496 t.
Station.push_back(
sn.stations[i].name);
SolverAUTO.listValidMethods: the method names THIS MODEL can actually run.
std::string method_used()
getMethodUsed(): the method the solve actually resolved to.
std::vector< std::string > list_valid_methods() const
listValidMethods(): the methods this solver advertises on this model.
const AvgTable & avg_table()
getAvgTable(): the average table, solving on first demand.
BoundsTable bounds_table()
getBoundsTable(): the per-class queue-length and throughput bounds.
static void print_inf_gen(const Matrix< double > &Q, const Matrix< double > &space)
CTMC.printInfGen(Q, SS): the generator beside the state it belongs to.
Matrix< double > generator()
getGenerator(): the infinitesimal generator over that space.
double prob_aggr(std::size_t node, const std::vector< double > &state)
getProbAggr(node, state): the aggregate marginal of one state.
Matrix< double > state_space()
getStateSpace(): the aggregate state space, one row per state.
std::vector< double > marg_aggr(std::size_t node)
getProbStateAggr(node): the marginal over every state of one station.
std::vector< std::vector< CdfCurve > > cdf_respt()
getCdfRespT(): the response-time CDF per (station, class).
std::vector< std::vector< CdfCurve > > cdf_respt()
getCdfRespT(): the response-time CDF per (station, class).
TranAvg tran_avg()
getTranAvg(): the transient mean queue length per station.
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
std::vector< JobClass > classes
const NetworkStruct< T > & get_struct()
The refreshed struct, MATLAB's model.getStruct().
The fluid solver's outermost entry point: @@SolverFLD/runAnalyzer.m's method resolution over solver_f...
The log-driven half of SolverJMT: linkAndLog, parseLogs, parseTranState, parseTranRespT,...
AutoSolver auto_choose_avg_solver(const qn::NetworkStruct< T > &sn)
const char * auto_solver_name(AutoSolver s)
std::vector< std::string > auto_list_valid_methods(const qn::NetworkStruct< T > &sn)
SolverAUTO.listValidMethods: every method name this model can be asked for.
BaBounds< T > ba_bounds(const qn::NetworkStruct< T > &L, const BaOptions &opt)
Port of SolverBA.getBounds.
mva::AvgResult< T > solver_ba_run_analyzer(const qn::NetworkStruct< T > &L, const BaOptions &opt_in)
Port of @@SolverBA/runAnalyzer.m for the lang='matlab' path.
std::vector< std::string > list_valid_methods()
Port of SolverBA.listValidMethods.
std::vector< std::string > list_valid_methods()
Port of SolverCTMC.listValidMethods.
CtmcGenerator< T > ctmc_get_infgen(const NetworkStruct< T > &sn, const CtmcSolution< T > &d)
@@SolverCTMC/getInfGen.m, a pure alias of getGenerator in the reference.
std::vector< std::vector< CdfCurve< T > > > solver_ctmc_cdf_respt(const NetworkStruct< T > &sn, const CtmcOptions &opt)
Port of @@SolverCTMC/getCdfRespT.m: the per-(station, class) response-time CDF, indexed [ist-1][r-1].
CtmcStateSpace< T > ctmc_get_state_space(const NetworkStruct< T > &, const CtmcSolution< T > &d)
Port of @@SolverCTMC/getStateSpace.m.
Matrix< T > ctmc_get_state_space_aggr(const NetworkStruct< T > &sn, const CtmcOptions &opt)
Port of @@SolverCTMC/getStateSpaceAggr.m: the per-(station, class) job counts of every state,...
CtmcSolution< T > solver_ctmc_analyzer(const NetworkStruct< T > &sn_in, const CtmcOptions &opt)
Port of solver_ctmc_analyzer.m plus the fork-join wrapper of @@SolverCTMC/runAnalyzer....
mva::AvgResult< T > solver_ctmc_run_analyzer_any(const NetworkStruct< T > &sn, const CtmcOptions &opt)
Solve on whichever path applies and format, mirroring solver_ctmc_run_analyzer.
std::vector< std::string > fluid_list_valid_methods()
Port of SolverFLD.listValidMethods.
std::vector< FluidTranPoint > solver_fluid_tran_avg(const qn::NetworkStruct< T > &sn, const FluidOptions &opt, std::size_t points=101)
getTranAvg on the first-order closing drift, over that horizon.
FluidSolution solver_fluid_run_analyzer(const qn::NetworkStruct< T > &sn, const FluidOptions &opt, qn::NetworkStruct< T > *sn_out=nullptr, qn::NetworkStruct< T > *refreshed_out=nullptr, solvers::CacheMetrics< T > *cache_out=nullptr)
Port of @@SolverFLD/runAnalyzer.m: resolve the method, route to the function the reference routes to,...
std::vector< std::vector< FluidPassage > > solver_fluid_cdf_respt(const qn::NetworkStruct< T > &sn, const FluidOptions &opt, std::size_t points=201)
Port of @@SolverFLD/getCdfRespT: the response-time law of every (station, class) pair,...
std::vector< std::string > jmt_list_valid_methods()
Port of SolverJMT.listValidMethods.
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::vector< std::string > list_valid_methods()
Port of SolverLDES.listValidMethods.
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< std::string > list_valid_methods()
Port of SolverMAM.listValidMethods.
mva::AvgResult< T > solver_mam_run_analyzer(const qn::NetworkStruct< T > &L, const MamOptions &opt)
Port of @@SolverMAM/runAnalyzer.m for the lang='matlab' path: solve, then apply the metric filter @@N...
Matrix< T > sn_get_residt_from_respt(const qn::NetworkStruct< T > &L, const Matrix< T > &RN)
Port of sn_get_residt_from_respt: the per-JOB residence time.
std::vector< std::string > list_valid_methods(const qn::NetworkStruct< T > &L)
Port of SolverMVA.listValidMethods.
Matrix< T > sn_get_arvr_from_tput(const qn::NetworkStruct< T > &L, const Matrix< T > &TN)
AvgResult< T > solver_mva_run_analyzer(const qn::NetworkStruct< T > &L, const MvaOptions &opt_in, const Matrix< T > &init_sol)
Port of @@SolverMVA/runAnalyzer.m for the lang='matlab' path: gate, solve, convert,...
mva::AvgResult< T > solver_nc_run_analyzer(const qn::NetworkStruct< T > &L_in, const NcSolverOptions &opt_in)
Port of @@SolverNC/runAnalyzer.m for the lang='matlab' path: solve, then apply the metric filter @@Ne...
std::vector< std::string > list_valid_methods()
Port of SolverNC.listValidMethods.
std::vector< std::string > list_valid_methods()
Port of SolverSSA.listValidMethods.
SsaSolution solver_ssa(const qn::NetworkStruct< T > &sn, const SsaOptions &opt, std::vector< SsaCacheRatio > *cache=nullptr)
solver_ssa_analyzer.m: choose the method.
The solver API a user writes, spelled as its Python twin.
The SolverAUTO chooser: which solver a model is handed to.
The SolverBA class surface: @@SolverBA/runAnalyzer.m, listValidMethods, getBounds and getBoundsTable.
Port of solver_ctmc_analyzer.m and the parts of @@SolverCTMC/runAnalyzer.m that surround one solve: t...
Port of @@SolverCTMC/getCdfRespT.m and @@SolverCTMC/getCdfSysRespT.m: the exact distribution of the r...
The remaining @@SolverCTMC accessors: getGenerator / getInfGen, getStateSpace / getStateSpaceAggr and...
The SolverCTMC probability family: solver_ctmc_joint, _jointaggr, _marg, _margaggr,...
Port of solver_ctmc_fcr_waitq.m: the reachability-built generator of a model whose finite capacity re...
SolverFluid: the closing method, a port of solver_fluid.m, solver_fluid_iteration....
Port of SolverJMT, the Java Modelling Tools client.
Port of SolverLDES, the discrete-event simulator, as its C++ client.
The SolverMAM class surface: @@SolverMAM/runAnalyzer.m and the gates around it.
The SolverMVA class surface: @@SolverMVA/runAnalyzer.m and the gates around it.
The SolverNC class surface: @@SolverNC/runAnalyzer.m and the gates around it.
The SolverSSA entry surface: a port of @@SolverSSA/runAnalyzer.m's method whitelist,...
getAvgTable, one row per (station, class) that carries a metric.
std::vector< double > ArvR
std::vector< double > Tput
std::vector< double > ResidT
std::vector< double > RespT
std::vector< double > Util
std::vector< std::string > Station
std::vector< double > column(const std::string &column) const
The column of a station over every class it has a row for.
std::vector< double > SysTput
std::vector< std::string > JobClass
std::string warning
The reference's own warning text, empty when it did not warn.
double get(const std::string &column, const std::string &station, const std::string &jobclass) const
One cell of the table, by station and class NAME; NaN when absent.
std::vector< double > ListCost
getAvgCacheTable's ListCost column; empty on a model without item sizes.
std::vector< double > SysRespT
std::vector< std::string > SysClass
getAvgSysTable: system response time and throughput, per class.
std::vector< double > QLen
SolverBA(model, method).getBoundsTable().
std::vector< double > Tlower
std::vector< double > Qupper
std::vector< std::string > Station
std::vector< double > Qlower
std::vector< std::string > JobClass
std::vector< double > Tupper
The knobs a solver reads; a negative or empty field keeps the engine default.
bool keep
JMT options.keep: leave the scratch directory in place after the solve.
std::string multiserver
The options.config fields of the MVA / NC / fluid families.
int level
SolverBA options.level.
std::string fork_join
MVA / NC options.config.fork_join: 'default'/'mmt'/'fjt' or 'ht'.
std::string state_space_gen
SSA options.config.state_space_gen.
getTranAvg: the transient mean queue length per (station, class).
std::vector< std::string > label
the (station, class) of each column
std::vector< std::vector< double > > QNt
[step][station*class]
std::vector< double > t
the time axis
Port of SolverBA.getBounds: the {lower,upper} bracket of a family.
std::vector< std::vector< bool > > keep
getBoundsTable's row filter, (M x K): whether the (station, class) pair earns a row.
Matrix< T > Qupper
(M x K), all-NaN on a side the family lacks
The options SolverBA reads.
The SolverCTMC knobs this port honours.
Everything one CTMC solve produces.
std::vector< T > pi
stationary distribution over chain.space
Controls, defaulting to SolverOptions('Fluid') in the reference.
What the analyzer returns, in the same shape as the MVA solver's result.
The options of one JMT solve, SolverOptions('JMT') restricted to what is read.
The result of a JMT solve: the shared AvgResult plus what only JMT reports.
The knobs of one LDES run.
One ldes-result document, parsed.
The options SolverMAM reads.
The metrics getAvg returns, after filtering.
Matrix< T > RN
response time, per visit
std::string warning
The reference's own warning text, verbatim, empty when it did not warn.
Matrix< T > UN
utilization
std::vector< T > listcost
(h) mean storage cost held by each cache list, K_j = sum_i sigma_i pi_ij, filled only by the NC cache...
std::optional< double > lognormconst
@@SolverNC/getProbNormConstAggr, i.e.
Matrix< T > WN
residence time, per job
std::string actualmethod
the algorithm that ran
Matrix< T > QN
queue length
std::vector< T > CN
system response time per class
std::vector< T > XN
system throughput per class
Matrix< T > AN
arrival rate
The options SolverMVA reads.
Controls, defaulting to SolverOptions('NC') in the reference.
Controls, defaulting to SolverOptions('SSA') in the reference.
What the analyzer returns, in the same shape as the MVA and fluid results.
std::string method
The concrete algorithm, as the reference's method.