5#ifndef LINE_SOLVERS_BA_SOLVER_BA_RUNNER_H
6#define LINE_SOLVERS_BA_SOLVER_BA_RUNNER_H
54using lang::GlobalConstants;
62 if (method ==
"default")
return "gb.upper";
63 if (method ==
"auto")
return "auto.upper";
64 if (method ==
"lr")
return "lr.upper";
65 if (method ==
"qr")
return "qrf.mmi";
88 return !(method.rfind(
"qrf.bas", 0) == 0 || method.rfind(
"qrf.rsrd", 0) == 0 ||
89 method.rfind(
"spnlp", 0) == 0);
106 return ::line::method_registry::methods(
"BA");
137 typedef std::pair<std::string, std::string> R;
140 return R(
"",
"the QRF blocking bounds are derived for a single-class closed network,"
141 " which this model is not.");
142 for (std::size_t r = 0; r < L.
classes.size(); ++r)
143 if (!std::isfinite(L.
classes[r].population))
144 return R(
"",
"the QRF blocking bounds are derived for a single-class closed"
145 " network, which this model is not.");
146 for (std::size_t i = 0; i < L.
stations.size(); ++i) {
147 if (L.
stations[i].sched == SchedStrategy::INF)
148 return R(
"",
"the QRF blocking bounds model every station as a single server and"
149 " have no infinite-server notion, so a delay station rules them out.");
151 return R(
"",
"the QRF blocking bounds model every station as a single server, so a"
152 " multiserver station rules them out.");
157 for (std::size_t i = 0; i < L.
stations.size(); ++i) {
158 if (L.
service[i][0].disabled) { Ktot += 1;
continue; }
160 Ktot += mp.
D0.rows() == 0 ? 1 :
static_cast<int>(mp.
D0.rows());
163 if (!blk.msg.
empty())
return R(
"", blk.msg);
164 return R(
"qrf.bas",
"");
169 return method ==
"default" || method ==
"auto" || method ==
"auto.upper";
185 if (!routed.first.empty()) resolved = routed.first;
218 std::vector<std::string> structural;
219 for (std::size_t i = 0; i < all.size(); ++i)
221 structural.push_back(all[i]);
232 bool isPetri =
false;
233 for (std::size_t i = 0; i < L.
nodes.size() && !isPetri; ++i)
236 std::vector<std::string> sieved;
237 for (std::size_t i = 0; i < all.size(); ++i)
240 if (isPetri)
return all;
243 for (std::size_t r = 0; reducible && r < L.
classes.size(); ++r)
244 if (!std::isfinite(L.
classes[r].population)) reducible =
false;
245 bool closedSingleClass = reducible;
246 for (std::size_t i = 0; reducible && i < L.
stations.size(); ++i) {
247 if (L.
stations[i].sched == SchedStrategy::INF)
249 else if (L.
stations[i].nservers > 1.0)
260 const bool ldReducible =
267 bool fullyOpen = !L.
classes.empty();
268 for (std::size_t r = 0; fullyOpen && r < L.
classes.size(); ++r)
269 if (std::isfinite(L.
classes[r].population)) fullyOpen =
false;
270 bool bptOk = fullyOpen;
271 for (std::size_t i = 0; bptOk && i < L.
stations.size(); ++i) {
272 if (L.
stations[i].nodetype == qn::NodeType::Source)
continue;
273 if (L.
stations[i].sched == SchedStrategy::INF)
275 else if (L.
stations[i].nservers > 1.0)
278 std::vector<std::string> keep;
286 const char*
const open_fams[] = {
"bpt.lower",
294 "bgt.upper",
"snc.upper"};
295 for (
const char* nm : open_fams)
296 if (std::find(all.begin(), all.end(), std::string(nm)) != all.end())
300 for (std::size_t i = 0; i < all.size(); ++i) {
301 const std::string& m = all[i];
302 if (m ==
"bpt.lower" || m ==
"bgt.upper" || m ==
"snc.upper")
continue;
307 if (ldReducible && (m ==
"qrf.mmi.ld" || m ==
"qrf.mmi.linear")) {
316 if (m ==
"qr" || m ==
"lr" || m.compare(0, 3,
"lr.") == 0 ||
317 m.compare(0, 4,
"qrf.") == 0 || m.compare(0, 7,
"mapamva") == 0)
329 std::vector<std::string> unblocked;
335 for (std::size_t i = 0; i < keep.size(); ++i)
349 if (std::find(valid.begin(), valid.end(), m) != valid.end())
return;
368 opt_in.
method.compare(0, 3,
"bgt") != 0 && opt_in.
method.compare(0, 3,
"snc") != 0 &&
382 std::string blocking_why;
390 blocking_why = routed.second;
391 if (!routed.first.empty())
opt.method = routed.first;
396 "SolverBA: method '" + opt_in.
method +
397 "' does not support finite-buffer blocking: every SolverBA bound family but the"
398 " QRF blocking ones is parameterized by demands and a population alone, so it"
399 " bounds the model as if its buffers were unbounded. Use SolverMVA with method"
400 " 'sqd', an exact solver (CTMC, SSA, JMT, LDES), or the QRF blocking bounds"
401 " 'qrf.bas'/'qrf.rsrd', which model the finite buffer" +
402 (blocking_why.empty()
404 :
". The QRF blocking bounds do not apply here either: " + blocking_why));
413 const bool qrf = detail::is_qrf_noblo_method(
opt.method) ||
414 detail::is_qrf_lp_method(
opt.method) ||
415 detail::is_qrf_bas_nlp_method(
opt.method);
422 std::vector<std::vector<bool>> mask(M, std::vector<bool>(K,
false));
423 for (std::size_t i = 0; i < M; ++i)
424 for (std::size_t k = 0; k < K; ++k)
438 std::vector<std::vector<bool>> srcmask(M, std::vector<bool>(K,
false));
439 for (std::size_t i = 0; i < M; ++i)
440 if (L.
stations[i].nodetype == qn::NodeType::Source)
441 for (std::size_t k = 0; k < K; ++k) srcmask[i][k] =
true;
470 std::vector<std::vector<bool>>
keep;
485 const std::string fam = m.substr(0, m.find(
'.'));
492 if (!routed.first.empty())
494 "SolverBA: '" +
opt.method +
"' resolves to '" + routed.first +
495 "' on this model, which has a binding finite buffer, and that bound is"
496 " UPPER-only: there is no bracket to return. Call getAvg for the upper"
497 " bound, or SolverMVA with method 'sqd' for a point estimate");
500 auto listed = [&](
const std::string& x) {
501 return std::find(valid.begin(), valid.end(), x) != valid.end();
503 const double nan = std::numeric_limits<double>::quiet_NaN();
511 if (listed(fam +
".lower")) {
513 o.
method = fam +
".lower";
519 if (listed(fam +
".upper")) {
521 o.
method = fam +
".upper";
527 b.
keep.assign(M, std::vector<bool>(K,
true));
528 for (std::size_t i = 0; i < M; ++i)
529 for (std::size_t k = 0; k < K; ++k) {
531 bool any_present =
false, any_nonzero =
false;
532 for (
const T& x : v) {
537 b.
keep[i][k] = !any_present || any_nonzero;
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
std::vector< std::vector< Distrib< T > > > service
service[i][r], 0-based station and class; a disabled entry marks a pair never visited.
std::vector< JobClass > classes
std::vector< Station< T > > stations
stations[k-1] is the k-th station
std::vector< NodeDef > nodes
every node, in creation order
double nclosedjobs() const
sn.nclosedjobs: the total population of the closed classes.
The method names of each solver, in listing order.
bool sn_has_blocking(const qn::NetworkStruct< T > &sn)
Defined below, after sn_is_mm1k_loss, which it exempts.
BaBounds< T > ba_bounds(const qn::NetworkStruct< T > &L, const BaOptions &opt)
Port of SolverBA.getBounds.
BaSolution< T > solver_ba_qrf_analyzer(const qn::NetworkStruct< T > &L, const BaOptions &opt)
Port of solver_ba_qrf_analyzer.
bool is_default_request(const std::string &method)
True for the aliases whose meaning a blocked model is allowed to change.
bool ignores_blocking(const std::string &method)
Whether METHOD bounds a model as if its buffers were unbounded.
std::string resolve_model_method(const qn::NetworkStruct< T > &L, const std::string &method)
Port of ba_resolve_model_method.m (SolverBA.resolveMethod): the method METHOD runs as on THIS model.
std::pair< std::string, std::string > blocking_default(const qn::NetworkStruct< T > &L)
What default/auto must mean on a model with finite buffers: the QRF BAS bound, or nothing.
std::string method_refusal(const qn::NetworkStruct< T > &L, const std::string &method)
The STRUCTURAL premises of the SolverBA bound families, in one place: the reason METHOD cannot bound ...
BaSolution< T > solver_ba_analyzer(const qn::NetworkStruct< T > &L, const BaOptions &opt)
Port of solver_ba_analyzer.
void check_method(const std::string &method)
Port of runAnalyzer's method gate: an unlisted name is refused by name.
BaSolution< T > solver_ba_spnlp_analyzer(const qn::NetworkStruct< T > &L, const BaOptions &opt)
Moment-relaxation LP bounds for a stochastic Petri net.
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::string method_degenerate(const qn::NetworkStruct< T > &L, const std::string &method)
Whether METHOD APPLIES to L but its bound carries no information there, and why.
std::vector< std::string > list_valid_methods()
Port of SolverBA.listValidMethods.
bool is_spnlp_method(const std::string &method)
Whether a resolved method name belongs to the Petri-net LP family.
std::string resolve_method(const std::string &method)
Port of runAnalyzer's method aliases: default is the geometric upper bound, bare auto is the AUTO com...
mam::Map< T > dist_to_map(const Distrib< T > &d)
The (D0,D1) pair that reaches sn.proc.
Matrix< T > filter_metric(const qn::NetworkStruct< T > &L, const Matrix< T > &metric, MetricKind kind, const std::vector< std::vector< bool > > *zero_mask)
Port of filterMetric: what @@NetworkSolver/getAvg does between the analyzer and the caller.
Matrix< T > sn_get_arvr_from_tput(const qn::NetworkStruct< T > &L, const Matrix< T > &TN)
Port of sn_get_arvr_from_tput: the arrival rate each station sees, from the throughputs and the class...
QrfBlocking sn_to_qrf_blocking(const qn::NetworkStruct< T > &sn, int Ktot, double max_vars=kQrfDefaultMaxVars)
The QRF BAS blocking tables (f, MR, BB, MM, ZZ, MM1), derived from an sn.
QrfAlpha sn_to_qrf_alpha(const qn::NetworkStruct< T > &L)
ld stays TRUE through a refusal: the model IS load dependent, and the caller has to tell "no arm serv...
Conservation laws of a layered queueing network, enumerated from its structure.
A queueing network and its refreshed NetworkStruct.
Ports of the sn_has_* / sn_is_* predicate family of matlab/src/api/sn.
The QRF load-dependent rate scaling alpha(i,n), derived from an sn.
The QRF BAS blocking tables (f, MR, BB, MM, ZZ, MM1), derived from an sn.
Port of matlab/src/solvers/BA/solver_ba_analyzer.m, the bound-analysis handler behind SolverBA.
Port of matlab/src/solvers/BA/solver_ba_qrf_analyzer.m, the adapter that bridges the sn struct to the...
Linear-programming bounds on the mean marking and the throughputs of a stochastic timed Petri net.
The DECLARED side of the gate: one feature set per solver.
The SolverMVA class surface: @@SolverMVA/runAnalyzer.m and the gates around it.
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
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.
std::string method
Bound method; default resolves to gb.upper in the runner.
Class-level results, the [Q,U,R,T,C,X] of solver_ba_analyzer.
static constexpr double FineTol
A MAP as the pair of matrices (D0, D1).
The metrics getAvg returns, after filtering.
Matrix< T > RN
response time, per visit
Matrix< T > UN
utilization
Matrix< T > WN
residence time, per job
std::string method
the method asked for
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
std::string msg
empty on success
The derived blocking tables, in the reference's 1-based queue indexing.