LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
solver_facade.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5
6/**
7 * @file
8 * The one translation unit that instantiates the solver stack for the facade.
9 *
10 * `line/solvers/solver.h` declares a `double`-only, non-template solver API so
11 * that this file can carry every body: a caller including that header pays for
12 * none of the template instantiation below, and `line_mp_api` pays for it once
13 * for the CLI, the tests and the examples together.
14 *
15 * Every entry point forwards to the runner the CLI calls, so a program written
16 * against the facade and `line-cli -s <solver>` on the same model produce the
17 * same numbers by construction. Nothing is computed here beyond the reshaping
18 * the tables need.
19 */
20
21#include "line/solvers/solver.h"
22
23#include <algorithm>
24#include <cctype>
25#include <cstdio>
26#include <limits>
27#include <map>
28#include <sstream>
29#include <utility>
30
48
49namespace line {
50
51// ---------------------------------------------------------------------------
52// AvgTable
53// ---------------------------------------------------------------------------
54
55double AvgTable::get(const std::string& col, const std::string& station,
56 const std::string& jobclass) const {
57 for (std::size_t i = 0; i < Station.size(); ++i) {
58 if (Station[i] != station || JobClass[i] != jobclass) continue;
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 + "'");
66 }
67 return std::numeric_limits<double>::quiet_NaN();
68}
69
70std::vector<double> AvgTable::column(const std::string& col) const {
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 + "'");
78}
79
80namespace {
81
82/** Fill the label columns and the per-class system metrics of a table. */
83void fill_table(AvgTable& t, const qn::NetworkStruct<double>& sn, const mva::AvgResult<double>& r) {
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;
89 t.Station.push_back(sn.stations[i].name);
90 t.JobClass.push_back(sn.classes[c].name);
91 t.QLen.push_back(q);
92 t.Util.push_back(u);
93 t.RespT.push_back(rt);
94 t.ResidT.push_back(w);
95 t.ArvR.push_back(a);
96 t.Tput.push_back(x);
97 }
98 for (std::size_t c = 0; c < sn.nclasses && c < r.CN.size(); ++c) {
99 t.SysClass.push_back(sn.classes[c].name);
100 t.SysRespT.push_back(r.CN[c]);
101 t.SysTput.push_back(c < r.XN.size() ? r.XN[c] : 0.0);
102 }
103 t.iter = r.iter;
104 t.warning = r.warning;
105 t.ListCost = r.listcost;
106 if (r.lognormconst.has_value()) {
107 t.has_lognormconst = true;
108 t.lognormconst = r.lognormconst.value();
109 }
110}
111
112/**
113 * The same fill for a solver whose solution type is not `mva::AvgResult`.
114 *
115 * THE SSA AND FLUID ARMS OWE BOTH DERIVED COLUMNS. Neither analyzer reports a
116 * residence time or an arrival rate of its own, and neither is a copy of its
117 * neighbour: ResidT is the per-JOB time and RespT the per-VISIT one, and they
118 * agree only where every station is visited once per cycle. ArvR is a FLOW and
119 * parts from the throughput at any station a job leaves by another route.
120 * `sn_get_residt_from_respt` and `sn_get_arvr_from_tput` are the reference's own
121 * conversions and are what the CLI's `-s fluid` and `-s ssa` arms apply. A
122 * Source's ArvR stays zero: nothing arrives TO it.
123 */
124template <class Sol>
125void fill_table_sim(AvgTable& t, const qn::NetworkStruct<double>& sn, const Sol& r) {
126 const std::size_t M = sn.nstations, K = sn.nclasses;
127 Matrix<double> RN(M, K), TN(M, K);
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);
132 }
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);
138 const bool is_source = sn.stations[i].sched == lang::SchedStrategy::EXT;
139 const double w = WN(i, c), a = is_source ? 0.0 : AN(i, c);
140 // The all-zero row test over ALL SIX columns, as `avg_rows` and the
141 // reference make it: a station only ARRIVALS reach still has a row.
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);
145 t.QLen.push_back(q);
146 t.Util.push_back(u);
147 t.RespT.push_back(rt);
148 t.ResidT.push_back(w);
149 t.ArvR.push_back(a);
150 t.Tput.push_back(x);
151 }
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);
156 }
157}
158
159/**
160 * The LDES fill. Its solution type carries the six metrics separately and its
161 * per-class CN/XN are (1 x nclasses) MATRICES rather than vectors, so neither
162 * `fill_table` nor `fill_table_sim` can read it.
163 *
164 * ResidT IS RECOMPUTED RATHER THAN TAKEN, which is what the CLI's `-a avg` LDES
165 * arm does and for the same reason: the engine counts ONE VISIT PER STATION, so
166 * the residence time it reports is its response time wherever a visit ratio is
167 * not 1.
168 */
169void fill_table_ldes(AvgTable& t, const qn::NetworkStruct<double>& sn,
170 const ldes::LdesResult& r) {
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);
179 t.QLen.push_back(q);
180 t.Util.push_back(u);
181 t.RespT.push_back(rt);
182 t.ResidT.push_back(w);
183 t.ArvR.push_back(a);
184 t.Tput.push_back(x);
185 }
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);
190 }
191}
192
193ctmc::CtmcOptions ctmc_options(const SolverOptions& o) {
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;
199 return c;
200}
201
202fluid::FluidOptions fluid_options(const SolverOptions& o) {
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;
212 f.stiff = o.stiff;
213 return f;
214}
215
216/** `AUTO` resolves to the solver its feature set picks, as the CLI's auto arm does. */
217std::string resolve_auto(const std::string& name, const qn::NetworkStruct<double>& sn) {
218 if (name != "AUTO") return name;
220 std::transform(picked.begin(), picked.end(), picked.begin(), ::toupper);
221 if (picked == "FLUID") picked = "FLD";
222 return picked;
223}
224
225} // namespace
226
227// ---------------------------------------------------------------------------
228// NetworkSolver
229// ---------------------------------------------------------------------------
230
232 if (solved_) return table_;
233 AvgTable t;
234 t.solver = name_;
236 const SolverOptions& o = opts_;
237
238 if (name_ == "LQNS" || name_ == "QNS")
239 throw UnsupportedError("avg_table: '" + name_ +
240 "' analyses a LayeredNetwork rather than a Network");
241
242 const std::string name = resolve_auto(name_, sn);
243
244 if (name == "MVA") {
246 if (!o.method.empty()) opt.method = o.method;
247 if (o.tol >= 0.0) opt.tol = o.tol;
248 if (o.iter_tol >= 0.0) opt.iter_tol = o.iter_tol;
249 if (o.iter_max >= 0) opt.iter_max = o.iter_max;
250 if (!o.multiserver.empty()) opt.multiserver = o.multiserver;
251 if (!o.highvar.empty()) opt.highvar = o.highvar;
252 if (!o.np_priority.empty()) opt.np_priority = o.np_priority;
253 if (!o.fork_join.empty()) opt.fork_join = o.fork_join;
254 Matrix<double> init;
256 t.method = r.actualmethod;
257 fill_table(t, sn, r);
258 } else if (name == "NC") {
260 if (!o.method.empty()) opt.method = o.method;
261 if (o.tol >= 0.0) opt.tol = o.tol;
262 if (o.iter_tol >= 0.0) opt.iter_tol = o.iter_tol;
263 if (o.iter_max >= 0) opt.iter_max = o.iter_max;
264 if (!o.highvar.empty()) opt.highvar = o.highvar;
265 if (!o.multiserver.empty()) opt.multiserver = o.multiserver;
266 if (!o.fork_join.empty()) opt.fork_join = o.fork_join;
267 if (o.samples) opt.samples = o.samples;
268 if (o.seed) opt.seed = o.seed;
270 t.method = r.actualmethod;
271 fill_table(t, sn, r);
272 } else if (name == "CTMC") {
273 const ctmc::CtmcOptions opt = ctmc_options(o);
275 t.method = r.actualmethod;
276 fill_table(t, sn, r);
277 } else if (name == "MAM") {
279 if (!o.method.empty()) opt.method = o.method;
280 if (o.tol >= 0.0) opt.tol = o.tol;
281 if (o.iter_max >= 0) opt.iter_max = o.iter_max;
283 t.method = r.actualmethod;
284 fill_table(t, sn, r);
285 } else if (name == "BA") {
287 if (!o.method.empty()) opt.method = o.method;
288 opt.level = o.level;
290 t.method = r.actualmethod;
291 fill_table(t, sn, r);
292 } else if (name == "SSA") {
294 if (!o.method.empty()) opt.method = o.method;
295 if (o.samples) opt.samples = o.samples;
296 if (o.seed) opt.seed = o.seed;
297 if (!o.state_space_gen.empty()) opt.state_space_gen = o.state_space_gen;
298 opt.verbose = o.verbose;
300 t.method = r.method;
301 fill_table_sim(t, sn, r);
302 } else if (name == "FLD" || name == "FLUID") {
303 const fluid::FluidOptions opt = fluid_options(o);
305 t.method = r.method;
306 t.iter = static_cast<int>(r.iters);
307 fill_table_sim(t, sn, r);
308 } else if (name == "JMT") {
310 if (!o.method.empty()) opt.method = o.method;
311 if (o.samples) opt.samples = static_cast<double>(o.samples);
312 if (o.seed) opt.seed = static_cast<long>(o.seed);
313 opt.keep = o.keep;
314 opt.verbose = o.verbose;
316 t.method = r.avg.actualmethod;
317 fill_table(t, sn, r.avg);
318 } else if (name == "LDES") {
320 if (!o.method.empty()) opt.method = o.method;
321 if (o.samples) opt.samples = o.samples;
322 if (o.seed) opt.seed = static_cast<long>(o.seed);
323 opt.verbose = o.verbose;
325 t.method = opt.method;
326 fill_table_ldes(t, sn, r);
327 } else {
328 throw UnsupportedError("avg_table: unknown solver '" + name_ + "'");
329 }
330 table_ = t;
331 solved_ = true;
332 return table_;
333}
334
335std::string NetworkSolver::method_used() { return avg_table().method; }
336
337std::vector<std::string> NetworkSolver::list_valid_methods() const {
339 if (name_ == "MVA") return mva::list_valid_methods(sn);
340 if (name_ == "NC") return nc::list_valid_methods();
341 if (name_ == "CTMC") return ctmc::list_valid_methods();
342 if (name_ == "MAM") return mam::list_valid_methods();
343 // The model-aware overload, not the bare one: the reduction bounds are
344 // derived for a single-class closed network of single servers and the three
345 // open-network bounds for its mirror image, so the list a caller may act on
346 // depends on the model. `SolverBA` gates on exactly this list.
347 if (name_ == "BA") return ba::list_valid_methods(sn);
348 if (name_ == "FLD") return fluid::fluid_list_valid_methods();
349 if (name_ == "SSA") return ssa::list_valid_methods();
350 if (name_ == "JMT") return jmt::jmt_list_valid_methods();
351 if (name_ == "LDES") return ldes::list_valid_methods();
352 // AUTO answers about every family it can delegate to, gated by each one's
353 // feature set on this model; see `auto_methods.h`.
354 if (name_ == "AUTO") return autosolver::auto_list_valid_methods(sn);
355 throw UnsupportedError("list_valid_methods: unknown solver '" + name_ + "'");
356}
357
358// ---------------------------------------------------------------------------
359// SolverCTMC
360// ---------------------------------------------------------------------------
361
367
375
376double SolverCTMC::prob_aggr(std::size_t node, const std::vector<double>& state) {
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");
384 double p = 0.0;
385 for (std::size_t s = 0; s < A.rows(); ++s) {
386 bool hit = true;
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];
389 }
390 return p;
391}
392
393std::vector<double> SolverCTMC::marg_aggr(std::size_t node) {
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) {
402 double tot = 0.0;
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));
405 }
406 std::vector<double> pmf(nmax + 1, 0.0);
407 for (std::size_t s = 0; s < A.rows(); ++s) {
408 double tot = 0.0;
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];
411 }
412 return pmf;
413}
414
415std::vector<std::vector<CdfCurve> > SolverCTMC::cdf_respt() {
417 std::vector<std::vector<CdfCurve> > out(sn.nstations, std::vector<CdfCurve>(sn.nclasses));
418 const std::vector<std::vector<ctmc::CdfCurve<double> > > R =
419 ctmc::solver_ctmc_cdf_respt(sn, ctmc_options(opts_));
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;
424 }
425 return out;
426}
427
429 std::printf("%8s %-28s %s\n", "State", "Marking", "Rates (to: rate)");
430 for (std::size_t i = 0; i < Q.rows(); ++i) {
431 std::string mark;
432 if (i < space.rows()) {
433 std::ostringstream os;
434 os << "[";
435 for (std::size_t c = 0; c < space.cols(); ++c) os << (c ? " " : "") << space(i, c);
436 os << "]";
437 mark = os.str();
438 }
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));
442 std::printf("\n");
443 }
444}
445
446// ---------------------------------------------------------------------------
447// SolverFLD
448// ---------------------------------------------------------------------------
449
452 const std::vector<fluid::FluidTranPoint> pts =
453 fluid::solver_fluid_tran_avg(sn, fluid_options(opts_), 100);
454 TranAvg out;
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);
464 }
465 return out;
466}
467
468std::vector<std::vector<CdfCurve> > SolverFLD::cdf_respt() {
470 std::vector<std::vector<CdfCurve> > out(sn.nstations, std::vector<CdfCurve>(sn.nclasses));
471 const std::vector<std::vector<fluid::FluidPassage> > R =
472 fluid::solver_fluid_cdf_respt(sn, fluid_options(opts_));
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;
477 }
478 return out;
479}
480
481// ---------------------------------------------------------------------------
482// SolverBA
483// ---------------------------------------------------------------------------
484
488 if (!opts_.method.empty()) opt.method = opts_.method;
489 opt.level = opts_.level;
491 BoundsTable t;
492 t.method = opt.method;
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);
497 t.JobClass.push_back(sn.classes[c].name);
498 t.Qlower.push_back(b.Qlower(i, c));
499 t.Qupper.push_back(b.Qupper(i, c));
500 t.Tlower.push_back(b.Tlower(i, c));
501 t.Tupper.push_back(b.Tupper(i, c));
502 }
503 return t;
504}
505
506} // namespace line
SolverAUTO.listValidMethods: the method names THIS MODEL can actually run.
InputError(const std::string &what)
Definition error.h:39
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
AvgTable table_
Definition solver.h:96
SolverOptions opts_
Definition solver.h:95
std::string method_used()
getMethodUsed(): the method the solve actually resolved to.
Network * model_
Definition solver.h:93
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.
std::string name_
Definition solver.h:94
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)
Definition error.h:51
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.
Definition solver_jmt.h:838
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.
Definition solver_jmt.h:927
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.
Definition avg_table.h:34
std::vector< double > ArvR
Definition avg_table.h:36
std::vector< double > Tput
Definition avg_table.h:36
std::vector< double > ResidT
Definition avg_table.h:36
std::vector< double > RespT
Definition avg_table.h:36
double lognormconst
Definition avg_table.h:43
std::vector< double > Util
Definition avg_table.h:36
std::vector< std::string > Station
Definition avg_table.h:35
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
Definition avg_table.h:39
std::vector< std::string > JobClass
Definition avg_table.h:35
std::string warning
The reference's own warning text, empty when it did not warn.
Definition avg_table.h:47
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::string solver
Definition avg_table.h:40
std::string method
Definition avg_table.h:40
bool has_lognormconst
Definition avg_table.h:42
std::vector< double > ListCost
getAvgCacheTable's ListCost column; empty on a model without item sizes.
Definition avg_table.h:45
std::vector< double > SysRespT
Definition avg_table.h:39
std::vector< std::string > SysClass
getAvgSysTable: system response time and throughput, per class.
Definition avg_table.h:38
std::vector< double > QLen
Definition avg_table.h:36
SolverBA(model, method).getBoundsTable().
Definition avg_table.h:60
std::vector< double > Tlower
Definition avg_table.h:62
std::string method
Definition avg_table.h:63
std::vector< double > Qupper
Definition avg_table.h:62
std::vector< std::string > Station
Definition avg_table.h:61
std::vector< double > Qlower
Definition avg_table.h:62
std::vector< std::string > JobClass
Definition avg_table.h:61
std::vector< double > Tupper
Definition avg_table.h:62
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 np_priority
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).
Definition avg_table.h:72
std::vector< std::string > label
the (station, class) of each column
Definition avg_table.h:75
std::vector< std::vector< double > > QNt
[step][station*class]
Definition avg_table.h:74
std::vector< double > t
the time axis
Definition avg_table.h:73
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.
Definition solver_jmt.h:86
The result of a JMT solve: the shared AvgResult plus what only JMT reports.
Definition solver_jmt.h:493
mva::AvgResult< T > avg
Definition solver_jmt.h:494
The knobs of one LDES run.
One ldes-result document, parsed.
The options SolverMAM reads.
Definition mam_types.h:29
The metrics getAvg returns, after filtering.
Matrix< T > TN
throughput
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.
Definition mva_types.h:31
Controls, defaulting to SolverOptions('NC') in the reference.
Definition nc_types.h:33
Controls, defaulting to SolverOptions('SSA') in the reference.
Definition ssa_types.h:69
What the analyzer returns, in the same shape as the MVA and fluid results.
Definition ssa_types.h:101
std::string method
The concrete algorithm, as the reference's method.
Definition ssa_types.h:113