5#ifndef LINE_SOLVERS_AUTO_AUTO_METHODS_H
6#define LINE_SOLVERS_AUTO_AUTO_METHODS_H
79#include <initializer_list>
122 return {
"mva",
"nc",
"ctmc",
"fld",
"mam",
"ag",
"ba",
"ssa",
"ldes",
"jmt",
"lqns"};
138 if (family ==
"mva")
return {
"amva."};
150 const std::vector<std::string>& declared) {
152 if (name.size() > prefix.size() && name.compare(0, prefix.size(), prefix) == 0 &&
153 std::find(declared.begin(), declared.end(), name.substr(prefix.size())) !=
163inline bool auto_slot_of_family(
const std::string& family,
AutoSolver& out) {
191bool capacity_admits(
const std::string& family,
const qn::NetworkStruct<T>& sn,
192 const std::string& method) {
193 if (family !=
"mva" && family !=
"nc" && family !=
"fld" && family !=
"lqns")
return true;
195 if (family ==
"nc" && method ==
"mem") {
197 return ms.supported && ms.blocking;
210inline bool declared_feature_set(
const std::string& family,
const std::string& method,
211 qn::FeatureSet& declared, std::string& label) {
212 if (family ==
"mva") { declared =
qn::mva_feature_set(method); label =
"SolverMVA";
return true; }
213 if (family ==
"nc") { declared =
qn::nc_feature_set(method); label =
"SolverNC";
return true; }
214 if (family ==
"mam") { declared =
qn::mam_feature_set(method); label =
"SolverMAM";
return true; }
216 if (family ==
"ssa") { declared =
qn::ssa_feature_set(method); label =
"SolverSSA";
return true; }
217 if (family ==
"ctmc") { declared =
qn::ctmc_feature_set(method); label =
"SolverCTMC";
return true; }
218 if (family ==
"ldes") { declared =
qn::ldes_feature_set(method); label =
"SolverLDES";
return true; }
219 if (family ==
"ag") { declared =
qn::ag_feature_set(method); label =
"SolverAG";
return true; }
220 if (family ==
"ba") { declared =
qn::ba_feature_set(method); label =
"SolverBA";
return true; }
221 if (family ==
"jmt") { declared =
qn::jmt_feature_set(method); label =
"SolverJMT";
return true; }
222 if (family ==
"lqns") {
224 label =
"SolverLQNS";
253 return std::vector<std::string>();
268 const std::string& method) {
273 if (family ==
"nc" && (method ==
"cftp" || method ==
"cftp.approx")) {
275 if (!why.empty())
return why;
277 if (!detail::capacity_admits(family,
sn, method))
278 return "SolverAUTO: this method ignores the finite station capacity this model sets "
279 "(setCapacity / classCap), so it would report a capped station as unbounded.";
283 std::string gated = method;
284 if (family ==
"fld") {
285 const std::string m = fluid::detail::fluid_unqualify(method);
286 if (m ==
"rmf" || m ==
"refined") gated = fluid::detail::fluid_has_cache(
sn) ?
"rmf" :
"refined";
290 if (!detail::declared_feature_set(family, gated, declared, label))
291 return "SolverAUTO: the '" + family +
"' method family does not solve a flat Network.";
302 if (family ==
"nc") {
304 if (!ncr.empty())
return ncr;
316 if (family ==
"jmt") {
318 if (!why.empty())
return why;
320 if (family ==
"mam") {
322 if (!why.empty())
return why;
328 if (family ==
"ag") {
329 const std::string why = ag::runner_detail::method_refusal(
sn, method);
330 if (!why.empty())
return why;
335 if (family ==
"lqns") {
337 if (!why.empty())
return why;
347 if (family ==
"ba") {
349 if (!why.empty())
return "SolverBA: " + why;
351 if (family ==
"ctmc") {
354 const std::string why =
356 if (!why.empty())
return why;
365 if (family ==
"ctmc" || family ==
"ssa") {
367 if (!why.empty())
return why;
375 if (family ==
"ssa" && method ==
"nrm") {
376 const std::string why = ssa::detail::ssa_nrm_supports(
sn);
377 if (!why.empty())
return why;
379 if (family ==
"fld") {
384 if (!why.empty())
return why;
388 const std::string
fj = fluid::detail::fluid_forkjoin_supports(
sn, method);
389 if (!
fj.empty())
return fj;
397 if (detail::auto_slot_of_family(family, slot)) {
400 ": no engine for this solver is available in this build.";
404 ": 'exact' needs a product-form model, and this one has no product-form "
407 return "SolverCTMC: the state space of this model is too large to enumerate.";
408 return label +
": this solver refuses the model through its own structural check.";
416 const std::string& method) {
452 return {
"avg",
"tran",
"cdf",
"prob",
"tranprob",
"sample",
453 "cache",
"loss",
"orbit",
"moment",
"sens"};
458inline bool name_in(
const std::string& n, std::initializer_list<const char*> names) {
459 for (
const char* c : names)
460 if (n == c)
return true;
464inline bool starts_with(
const std::string& s,
const std::string& p) {
465 return s.size() >= p.size() && s.compare(0, p.size(), p) == 0;
483 if (name.empty())
return "";
485 if (g == name)
return g;
486 if (name ==
"any" || name ==
"all")
return "";
487 if (detail::name_in(name, {
"getTranAvg",
"getTranAvgVar",
"tranAvg"}))
return "tran";
488 if (detail::name_in(name, {
"getCdfRespT",
"getCdfPassT",
"getPerctRespT",
"getTranCdfPassT",
489 "getTranCdfRespT",
"getCdfSysRespT"}))
491 if (detail::name_in(name, {
"getTranProb",
"getTranProbSys",
"getTranProbAggr",
492 "getTranProbSysAggr"}))
494 if (detail::name_in(name, {
"getProb",
"getProbAggr",
"getProbSys",
"getProbSysAggr",
495 "getProbMarg",
"getProbNormConstAggr"}))
497 if (detail::name_in(name, {
"sample",
"sampleSys",
"sampleAggr",
"sampleSysAggr"}))
499 if (detail::name_in(name, {
"getAvgCacheTable",
"getAvgCacheT",
"getAvgItemTable",
500 "getAvgItemT",
"cacheAvgT",
"itemAvgT",
"aCaT",
"aIT"}))
502 if (detail::name_in(name, {
"getAvgLossTable",
"getAvgLossT",
"getAvgRegionLossTable",
503 "getAvgRegionLossT",
"lossAvgT",
"regionLossAvgT",
"aLT",
"aRLT"}))
505 if (detail::name_in(name, {
"getAvgOrbitTable",
"getAvgOrbitT",
"getAvgOrbit",
"orbitAvgT",
508 if (detail::name_in(name, {
"getMomentTable",
"getMomentChainTable",
"getMomentStationTable",
509 "getMomentT",
"getMomentChainT",
"getMomentStationT",
"momentT",
510 "momentChainT",
"momentStationT",
"mT",
"mCT",
"mST"}))
512 if (detail::name_in(name, {
"getSensitivityTable",
"getSensitivityT",
"sensitivityT",
"sT",
513 "getSensitivity",
"getSensitivityRanking"}))
517 if (detail::starts_with(name,
"getAvg") || detail::starts_with(name,
"avg") ||
518 detail::name_in(name, {
"getAvgSysRespT",
"getAvgSysTput",
"aT",
"aNT",
"aCT",
"aST",
545 if (family ==
"mva")
return {
"avg",
"prob",
"cache",
"orbit",
"moment",
"sens"};
546 if (family ==
"nc")
return {
"avg",
"cdf",
"prob",
"cache",
"moment",
"sens"};
547 if (family ==
"ctmc")
548 return {
"avg",
"tran",
"cdf",
"prob",
"tranprob",
"sample",
"cache",
"loss",
"orbit",
550 if (family ==
"fld")
return {
"avg",
"tran",
"cdf",
"prob",
"cache",
"sens"};
551 if (family ==
"mam")
return {
"avg",
"cdf"};
554 if (family ==
"ag")
return {
"avg"};
556 if (family ==
"ba")
return {
"avg"};
557 if (family ==
"ssa")
return {
"avg",
"cdf",
"prob",
"sample",
"loss"};
558 if (family ==
"ldes")
559 return {
"avg",
"tran",
"cdf",
"prob",
"sample",
"cache",
"loss",
"orbit"};
560 if (family ==
"jmt")
return {
"avg",
"tran",
"cdf",
"prob",
"tranprob",
"sample"};
575 if (family ==
"ssa" || family ==
"ldes")
return true;
577 if (family ==
"jmt") {
579 std::vector<std::string> toks;
580 for (
char ch : method) {
581 if (ch ==
'.' || ch ==
'/') {
585 tok +=
static_cast<char>(std::tolower(
static_cast<unsigned char>(ch)));
590 for (
const std::string& t : toks)
591 if (t ==
"jmva") jmva =
true;
592 if (!jmva)
return true;
593 for (
const std::string& t : toks)
594 if (t ==
"ls" || t ==
"mci" || t ==
"imci" || t ==
"sampling")
return true;
601inline std::string exact_if(
bool cond) {
return cond ?
"exact" :
"approx"; }
632 bool is_stochastic,
bool is_product_form,
633 bool is_qbd_shape,
bool has_cache =
false) {
636 if (family ==
"ba")
return "bound";
637 if (is_stochastic)
return "simulation";
638 if (family ==
"ctmc") {
642 if (method ==
"mdd")
return detail::exact_if(is_product_form);
645 if (family ==
"nc") {
652 if (detail::name_in(method, {
"exact",
"divdiff",
"ca",
"comom",
"comomld",
"rec",
"ms",
653 "cub",
"rgf",
"cftp"}))
654 return detail::exact_if(is_product_form && !has_cache);
657 if (family ==
"mva") {
660 if (detail::name_in(method, {
"exact",
"mva"}))
661 return detail::exact_if(is_product_form && !has_cache);
664 if (family ==
"jmt") {
667 if (detail::name_in(method, {
"jmva.mva",
"jmva.recal",
"jmva.comom",
"jmva.treeconv"}))
668 return detail::exact_if(is_product_form && !has_cache);
671 if (family ==
"mam") {
675 if (detail::name_in(method, {
"default",
"mna",
"ldqbd",
"bgchain",
"retrial"}))
676 return detail::exact_if(is_qbd_shape);
679 if (family ==
"ag") {
710 const std::string& metric = std::string(),
711 bool show_all =
false) {
713 if (group.empty() && !metric.empty() && metric !=
"any" && metric !=
"all") {
716 if (!groups.empty()) groups +=
", ";
723 throw InputError(
"'" + metric +
"' names no measure. Pass a group (" + groups +
724 ") or the accessor that returns it, e.g. 'getCdfRespT'.");
729 const bool is_product_form =
sn.has_product_form();
730 std::size_t nsources = 0;
733 const std::vector<double> njobs =
sn.njobs();
734 bool all_open = !njobs.empty();
735 for (
double n : njobs)
736 if (!std::isinf(n)) all_open =
false;
737 const bool is_qbd_shape = all_open && (
sn.nstations - nsources) == 1;
738 bool has_cache =
false;
740 if (nd.
nodetype == qn::NodeType::Cache) has_cache =
true;
742 std::vector<SolverCandidate> rows;
745 if (!group.empty() &&
746 std::find(groups.begin(), groups.end(), group) == groups.end())
748 std::string metric_list;
749 for (
const std::string& g : groups) {
750 if (!metric_list.empty()) metric_list +=
",";
754 for (
const std::string& name : declared) {
755 if (detail::starts_with(name, family +
".")) {
772 const bool ok = reason.empty();
773 if (!ok && !show_all)
continue;
776 row.method = family +
"." + name;
780 is_qbd_shape, has_cache);
781 row.metrics = metric_list;
782 row.reason = ok ? std::string() : reason;
792 const std::string& metric = std::string(),
793 bool show_all =
false) {
800 const std::string& metric = std::string(),
801 bool show_all =
false) {
811 if (rows.empty())
return "No solver method can analyze this model.\n";
812 std::vector<std::array<std::string, 6>> cells;
813 cells.push_back({
"Solver",
"Method",
"Runnable",
"Class",
"Metrics",
"Reason"});
815 cells.push_back({r.solver, r.method, r.runnable ?
"true" :
"false", r.method_class,
816 r.metrics, r.reason});
817 std::array<std::size_t, 6> width{};
818 for (
const auto& row : cells)
819 for (std::size_t c = 0; c < 5; ++c) width[c] = std::max(width[c], row[c].size());
821 for (
const auto& row : cells) {
823 for (std::size_t c = 0; c < 5; ++c)
line += row[c] + std::string(width[c] - row[c].size() + 2,
' ');
825 while (!
line.empty() &&
line.back() ==
' ')
line.pop_back();
855 std::vector<std::string> out{
"accurate",
"auto",
"bound",
"default",
856 "exact",
"fast",
"heur",
"sim"};
858 out.push_back(row.method);
859 out.push_back(row.solver);
861 std::sort(out.begin(), out.end());
862 out.erase(std::unique(out.begin(), out.end()), out.end());
A subset of the registry: MATLAB's SolverFeatureSet, whose list is a flag per field.
A network plus its refreshed NetworkStruct.
The exception types the port throws.
The language-feature gate: what a MODEL uses against what a SOLVER declares.
The fluid solver's outermost entry point: @@SolverFLD/runAnalyzer.m's method resolution over solver_f...
The option and result records of SolverLDES, the discrete-event simulator.
The flat-Network path of @@SolverLQNS: its qns methods, served by qnsolver of the RADS/LQNS distribut...
std::vector< std::string > list_valid_methods()
Every method SolverAG serves, as the other families expose theirs.
bool auto_supports(AutoSolver s, const qn::NetworkStruct< T > &sn, const std::string &token)
Solver.supports(model) for a candidate slot, tightened by the two method-level rules a flat feature s...
AutoSolver
The Network candidate slots, in the reference's slot order (SolverAUTO.m:41-50), which is also the or...
std::string auto_method_class(const std::string &family, const std::string &method, bool is_stochastic, bool is_product_form, bool is_qbd_shape, bool has_cache=false)
What KIND of answer a method returns: "exact", "approx", "bound" or "simulation".
std::vector< std::string > auto_network_family_names()
The method families that solve a flat Network, in SolverAUTO.familyNames' own order – which is also t...
std::string auto_metric_group_of(const std::string &name)
The measure group an accessor belongs to, "" when the name belongs to none.
bool auto_solver_is_available(AutoSolver s)
True when this port has an engine behind the slot at all.
std::string auto_family_refusal(const std::string &family, const qn::NetworkStruct< T > &sn, const std::string &method)
Solver.supportsModelMethod for a family method name: may THIS model run THIS method of THIS family?
std::string auto_find_solver_table(const std::vector< SolverCandidate > &rows)
The rows as an aligned text table, the form the CLI and a console caller want.
bool auto_is_stochastic_method(const std::string &family, const std::string &method)
Solver.isStochasticMethod for a family method name: does this method return seed-dependent estimates?
std::vector< std::string > auto_family_metrics(const std::string &family)
The measure groups a method family can answer.
std::vector< SolverCandidate > auto_find_method(const qn::NetworkStruct< T > &sn, const std::string &metric=std::string(), bool show_all=false)
Alias of auto_find_solver: the same table, asked for by method.
std::vector< std::string > auto_metric_groups()
The measure groups auto_find_solver reports on, in report order.
bool auto_family_supports(const std::string &family, const qn::NetworkStruct< T > &sn, const std::string &method)
const char * auto_solver_name(AutoSolver s)
std::vector< SolverCandidate > auto_find_solver(const qn::NetworkStruct< T > &sn, const std::string &metric=std::string(), bool show_all=false)
SolverAUTO.findSolver: which solvers and solver methods can analyze this model, and for the ones that...
std::vector< SolverCandidate > auto_help(const qn::NetworkStruct< T > &sn, const std::string &metric=std::string(), bool show_all=false)
Alias of auto_find_solver: what can this model be solved with?
std::vector< std::string > auto_list_valid_methods(const qn::NetworkStruct< T > &sn)
SolverAUTO.listValidMethods: every method name this model can be asked for.
std::vector< std::string > auto_family_methods(const std::string &family, const qn::NetworkStruct< T > &sn)
The methods a family declares ON THIS MODEL, empty when it declares none.
std::vector< std::string > auto_method_alias_prefixes(const std::string &family)
The prefixes under which a family advertises a SECOND SPELLING of a method it already declares plainl...
bool auto_is_method_alias(const std::string &family, const std::string &name, const std::vector< std::string > &declared)
Is name a second spelling of another method this family declares?
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 ...
std::vector< std::string > list_valid_methods()
Port of SolverBA.listValidMethods.
std::vector< std::string > list_valid_methods()
Port of SolverCTMC.listValidMethods.
std::string solver_ctmc_mdd_supports(const NetworkStruct< T > &sn)
Can the mdd decision-diagram method be asked for this model?
std::string fluid_qsys_horizon_supports(const std::string &method, const FluidOptions &opt)
The horizon rule the time-varying limits impose, as a public predicate a REPORT can ask: empty when m...
std::vector< std::string > fluid_list_valid_methods()
Port of SolverFLD.listValidMethods.
std::vector< std::string > jmt_list_valid_methods()
Port of SolverJMT.listValidMethods.
std::string jmt_method_refusal(const qn::NetworkStruct< T > &sn, const std::string &method, const JmtOptions &opt)
The structural half of SolverJMT's method gate; empty when admissible.
std::vector< std::string > list_valid_methods()
Port of SolverLDES.listValidMethods.
std::vector< std::string > qns_methods()
Port of SolverLQNS.listValidMethods on a flat Network.
std::string qns_method_refusal(const qn::NetworkStruct< T > &L, const std::string &method)
SolverLQNS.supportsModelMethod's structural rules on a Network, as the REASON they refuse,...
std::vector< std::string > list_valid_methods()
Port of SolverMAM.listValidMethods.
std::string mam_model_method_refusal(const qn::NetworkStruct< T > &L, const std::string &method)
check_model_method asked WITHOUT raising: the same verdict as a sentence.
std::vector< std::string > list_valid_methods(const qn::NetworkStruct< T > &L)
Port of SolverMVA.listValidMethods.
MemSupport solver_nc_mem_supports(const qn::NetworkStruct< T > &sn)
Port of solver_nc_mem_supports.m.
std::vector< std::string > list_valid_methods()
Port of SolverNC.listValidMethods.
bool is_stochastic_method(const std::string &method)
Port of SolverNC.isStochasticMethod.
std::string nc_method_refusal(const qn::NetworkStruct< T > &sn, const std::string &method, bool slotted=false, bool for_report=true)
May method run on this model?
std::string solver_nc_cftp_supports(const qn::NetworkStruct< T > &sn)
The cftp model-class gate as a public predicate.
FeatureSet ssa_feature_set(const std::string &)
SolverSSA.getFeatureSet, 98 MATLAB names.
FeatureSet ldes_feature_set(const std::string &)
SolverLDES.getFeatureSet, transcribed WHOLE.
FeatureSet fluid_feature_set(const std::string &method)
SolverFLD.getFeatureSet, transcribed, MINUS what the requested method cannot evaluate – the port of @...
FeatureSet jmt_feature_set(const std::string &method)
FeatureSet used_lang_features(const NetworkStruct< T > &sn)
FeatureSet lqns_network_feature_set(const std::string &)
SolverLQNS.getFeatureSet on a flat Network (its qns methods), transcribed WHOLE.
FeatureSet nc_feature_set(const std::string &method)
SolverNC.getFeatureSet, 48 names, transcribed unchanged.
FeatureSet ba_feature_set(const std::string &method)
std::string sn_fj_supports(const NetworkStruct< T > &sn)
Can the exact fork-join construction be asked for this model?
bool has_binding_capacity(const NetworkStruct< T > &sn)
getUsedLangFeatures: the features the MODEL uses.
FeatureSet ctmc_feature_set(const std::string &method)
SolverCTMC.getFeatureSet, the reference's 104 MATLAB names in full.
SupportResult feature_set_supports(const std::string &solver, const FeatureSet &declared, const FeatureSet &used)
SolverFeatureSet.supports: is every feature the model uses declared?
FeatureSet mam_feature_set(const std::string &method)
SolverMAM.getFeatureSet, the union of its four setTrue calls: 55 MATLAB names, WIDENED for 'default'/...
FeatureSet mva_feature_set(const std::string &raw_method)
FeatureSet ag_feature_set(const std::string &)
SolverAG.getFeatureSet: what the RCAT decomposition can represent.
std::vector< std::string > list_valid_methods()
Port of SolverSSA.listValidMethods.
Conservation laws of a layered queueing network, enumerated from its structure.
A queueing network and its refreshed NetworkStruct.
The gates and the dispatch of the agent-based (RCAT) solver.
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...
The mdd method of SolverCTMC: stationary analysis of a closed single-class network whose state space ...
The DECLARED side of the gate: one feature set per solver.
Port of SolverJMT, the Java Modelling Tools 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,...
One row of auto_find_solver: a (family, method) pair this model can be asked for, whether it runs,...
std::string method
the method name to pass, "mva.exact"
bool runnable
the model passes this method's own support gate
std::string metrics
the measure groups the family answers, comma-joined
std::string reason
why a refused pair was refused, "" when runnable
std::string solver
the method family: "mva", "ctmc", "ldes", ...
std::string method_class
"exact", "approx", "bound" or "simulation"
Controls, defaulting to SolverOptions('Fluid') in the reference.
The options of one JMT solve, SolverOptions('JMT') restricted to what is read.
One station of the network.
The outcome of the gate: the verdict, the offending features, the message.
std::string reason
empty when ok