5#ifndef LINE_SOLVERS_MAM_SOLVER_MAM_RUNNER_H
6#define LINE_SOLVERS_MAM_SOLVER_MAM_RUNNER_H
75using lang::GlobalConstants;
96 return {
"default",
"dec.source",
"dec.mmap",
"dec.poisson",
"mna",
"ldqbd",
"dec.source.mmap",
"bgchain",
"retrial"};
110 if (method !=
"inap" && method !=
"inapplus" && method !=
"inapinf"
111 && method !=
"exact") {
114 why =
"SolverMAM: the '" + method +
"' method moved to SolverAG: RCAT decomposes the "
115 "model into cooperating agents rather than decomposing traffic, and no MAM "
116 "algorithm shares its machinery. Solve it with -s ag";
123 if (std::find(valid.begin(), valid.end(), method) != valid.end())
return;
126 throw UnsupportedError(
"SolverMAM: the '" + method +
"' method is unsupported by this solver");
129namespace runner_detail {
146 if (is_discrete)
return;
147 for (std::size_t i = 0; i < L.
nstations; ++i)
148 for (std::size_t r = 0; r < L.
nclasses; ++r) {
151 if (basic_detail::is_markovian_type(p) || p == ProcessType::DET)
continue;
153 std::string(
"SolverMAM: station '") + L.
stations[i].name +
"' class '" +
155 " service process, which sn_nonmarkov_toph has no Markovian surrogate for: its "
156 "content is a piecewise-constant SCHEDULE, and collapsing it to one homogeneous "
157 "generator would answer for a stationary model the caller did not describe. Solve "
158 "it with SolverFLD or SolverLDES, which integrate the schedule");
168bool has_load_dependence(
const qn::NetworkStruct<T>& L) {
169 for (
const qn::Station<T>& st : L.stations)
170 if (!st.lldscaling.empty())
return true;
176bool has_signal_class(
const qn::NetworkStruct<T>& L) {
177 for (std::size_t r = 0; r < L.issignal.size(); ++r)
178 if (L.issignal[r])
return true;
184void check_model_method(
const qn::NetworkStruct<T>& L,
const std::string& method) {
197 if (has_signal_class(L)) {
199 "SolverMAM: the " + method +
" method does not support G-network signals: no MAM "
200 "algorithm reads issignal, so this method would solve the model with every signal "
201 "turned into an ordinary customer. Use SolverAG (-s ag), whose RCAT methods are "
202 "the only ones that model signals");
204 if (method ==
"mna") {
205 bool open =
false, closed =
false;
206 for (
const qn::JobClass& c : L.classes) {
207 if (std::isinf(c.population)) open =
true;
212 "SolverMAM: the mna method does not support mixed open/closed models");
219 for (
const qn::NodeDef& nd : L.nodes)
221 if (rs == qn::RoutingStrategy::RROBIN)
223 "SolverMAM: the mna method supports round-robin routing in open "
226 }
else if (method ==
"default") {
235 if (has_load_dependence(L) &&
236 !(L.setupparam.empty() && dispatch_detail::is_closed_delay_queue(L)))
238 "SolverMAM: this model uses load-dependent service rates outside the "
239 "single-class closed Delay+Queue shape that solver_mam_analyzer.m routes to the "
240 "level-dependent QBD (solver_mam_ldqbd); the 'default' method would otherwise "
241 "fall through to solver_mam_basic's dec.source decomposition, which does not "
242 "read the load-dependent scaling and would solve every level at the nominal "
243 "rate. Call method 'ldqbd' directly, which refuses by name if the shape still "
244 "does not fit, or restructure the model to the required shape");
245 }
else if (method ==
"ldqbd") {
247 throw UnsupportedError(
"SolverMAM: the ldqbd method requires a single-class model");
248 }
else if (method ==
"retrial") {
259 }
else if (method ==
"bgchain") {
264 bool hasClosed =
false;
265 for (std::size_t k = 0; k < L.nclasses; ++k) {
266 if (!std::isinf(L.classes[k].population)) hasClosed =
true;
270 "SolverMAM: the bgchain method requires at least one closed class: the background "
271 "chain IS the closed population vector, which a purely open model does not have. "
272 "Use the dec.source method");
275 bool prioSched =
false;
276 for (std::size_t i = 0; i < L.nstations; ++i) {
281 if (prioSched && L.has_distinct_priorities())
283 "SolverMAM: the bgchain method does not support class priorities: it aggregates "
284 "the open classes into one phase-type mixture per station, which cannot express a "
285 "priority order. Use the dec.source method");
288 "SolverMAM: the bgchain method does not support fork-join: the background chain "
289 "conserves the closed population per station, which a fork violates. Use the "
290 "dec.source method");
309 runner_detail::check_model_method(L, method);
310 }
catch (
const std::exception& e) {
311 return std::string(e.what());
313 return std::string();
323 runner_detail::check_model_method(L,
opt.method);
327 bool is_discrete =
false;
346 const bool preserve_det =
opt.preserve_det;
362 runner_detail::check_processes(Lc, is_discrete);
382 const std::string origmethod =
opt.method;
387 std::vector<std::vector<bool>> mask(M, std::vector<bool>(K,
false));
388 for (std::size_t i = 0; i < M; ++i)
389 for (std::size_t k = 0; k < K; ++k)
391 std::vector<std::vector<bool>> srcmask(M, std::vector<bool>(K,
false));
392 for (std::size_t i = 0; i < M; ++i)
393 if (L.
stations[i].nodetype == qn::NodeType::Source)
394 for (std::size_t k = 0; k < K; ++k) srcmask[i][k] =
true;
435 std::size_t ist, std::size_t jobclass,
458 runner_detail::check_model_method(L,
opt.method);
476 runner_detail::check_processes(*Lp,
false);
509 if (
opt.method !=
"default" &&
opt.method !=
"dec.source")
return false;
510 if (L.
fj.empty())
return false;
525 const std::vector<double>& percentiles) {
529 std::vector<std::vector<T>> out;
530 out.reserve(rd.size());
550 opt.method =
"ldqbd";
551 runner_detail::check_model_method(L,
opt.method);
554 runner_detail::check_processes(L,
false);
565 tranSet.
set(qn::Feature::FiniteCapacity);
UnsupportedError(const std::string &what)
A subset of the registry: MATLAB's SolverFeatureSet, whose list is a flag per field.
FeatureSet & set(Feature f)
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< std::vector< bool > > disabled
std::vector< JobClass > classes
std::vector< Station< T > > stations
stations[k-1] is the k-th station
std::vector< std::pair< std::size_t, std::size_t > > fj
fj(f,j): the Join node j that closes the Fork node f, 1-based.
The exception types the port throws.
Port of solver_mam_analyzer.m: one inner solve, choosing the analyzer that fits the model and the req...
The option and result types SolverMAM shares with its analyzers.
bool sn_has_nonmarkov(const qn::NetworkStruct< T > &sn, bool preserve_det=false)
Whether any law in the struct would be replaced, so a caller can skip copying the struct when there i...
@ Ph
Bernstein density fit: a genuine phase-type, shape-carrying.
@ Cme
concentrated ME plus exponential tail: two moments, exactly
void sn_nonmarkov_toph(qn::NetworkStruct< T > &sn, const NonmarkovOptions &opts=NonmarkovOptions())
Replace every non-Markovian service and firing law by a Markovian surrogate.
bool sn_is_discrete_time(const qn::NetworkStruct< T > &sn, const DiscreteTimeOptions &options, double *slot_length, DiscreteTimeInfo *info)
True when every law of sn is lattice-valued on slot_length.
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
RoutingStrategy
Routing strategies, with the values of MATLAB RoutingStrategy.
ProcessType
Distribution kinds, with the values of MATLAB ProcessType.
const char * process_to_text(ProcessType p)
The MATLAB ProcessType name, as sn.procid prints it.
std::vector< RespTCdf< T > > solver_mam_get_sjrn_t(const qn::NetworkStruct< T > &L, const MamOptions &opt)
@@SolverMAM/getSjrnT.m and sjrnT.m, both aliases of getCdfRespT.
qsys::BmapM1Result< T > solver_mam_getmamresult(const qn::NetworkStruct< T > &L)
Port of @@SolverMAM/getMAMResult.m: the matrix-analytic internals of a single-queue model,...
bool rcat_moved_to_ag(const std::string &method, std::string &why)
True for the four RCAT names that moved to SolverAG, with the redirect message.
void check_method(const std::string &method)
An unlisted method is refused; one that MOVED is redirected by name.
MamSolution< T > mam_dispatch(const qn::NetworkStruct< T > &L, const MamOptions &opt_in)
The ladder.
std::vector< T > mam_percentiles_from_cdf(const RespTCdf< T > &cdf, const std::vector< double > &pcts)
Port of the CDF path of @@SolverMAM/getPerctRespT.m: linear interpolation of the response-time CDF at...
TranResult< T > solver_mam_get_tran_avg(const qn::NetworkStruct< T > &L, const MamOptions &opt_in)
Port of @@SolverMAM/getTranAvg.m: transient queue length, utilization and throughput.
std::vector< std::string > list_valid_methods()
Port of SolverMAM.listValidMethods.
TranResult< T > solver_mam_transient_qbd(const qn::NetworkStruct< T > &L, const MamOptions &opt)
Port of solver_mam_transient_qbd.m.
MamSolution< T > solver_mam_solve(const qn::NetworkStruct< T > &L, const MamOptions &opt)
The gates and the dispatch of @@SolverMAM/runAnalyzer.m, without the metric filter.
std::vector< RespTCdf< T > > solver_mam_get_cdf_respt(const qn::NetworkStruct< T > &L, const MamOptions &opt)
@@SolverMAM/getCdfRespT.m: the response-time CDF per class.
std::vector< RespTCdf< T > > solver_mam_passage_time(const qn::NetworkStruct< T > &L, const MamOptions &opt)
Port of solver_mam_passage_time.m.
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...
ProbTable< T > solver_mam_get_prob(const qn::NetworkStruct< T > &L, const MamOptions &opt, std::size_t node, const mva::AvgResult< T > &avg)
@@SolverMAM/getProb.m: the joint (level, phase) table at a node.
bool mam_transient_qbd_applicable(const qn::NetworkStruct< T > &L)
Port of mam_transient_qbd_applicable.m: true when the Laplace-domain transient QBD should run instead...
MamFjInfo mam_fj_is_homogeneous(const qn::NetworkStruct< T > &L)
Port of fj_is_homogeneous.m.
std::vector< std::vector< T > > solver_mam_get_perct_respt(const qn::NetworkStruct< T > &L, const MamOptions &opt, const std::vector< double > &percentiles)
@@SolverMAM/getPerctRespT.m: response-time percentiles per class.
bool mam_has_fj_percentiles(const qn::NetworkStruct< T > &L, const MamOptions &opt)
Whether getPerctRespT reads the FJ_codes table rather than inverting a CDF.
std::vector< T > solver_mam_get_prob_marg(const qn::NetworkStruct< T > &L, const MamOptions &opt, std::size_t ist, std::size_t jobclass, const mva::AvgResult< T > &avg)
@@SolverMAM/getProbMarg.m: P(n jobs of one class) at a station.
TranResult< T > solver_mam_ldqbd_transient(const qn::NetworkStruct< T > &L, const MamOptions &opt)
Port of solver_mam_ldqbd_transient.m.
ProbTable< T > solver_mam_getprob(const qn::NetworkStruct< T > &L, const MamOptions &opt, std::size_t node, const mva::AvgResult< T > &avg)
Port of @@SolverMAM/getProb.m.
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::vector< T > > solver_mam_fj_percentiles(const qn::NetworkStruct< T > &L, const MamOptions &opt, const std::vector< double > &percentiles)
@@SolverMAM/getPerctRespT.m's fork-join path: the percentiles solver_mam_fj.m stores in percResults....
std::string mam_retrial_refusal(const qn::NetworkStruct< T > &L)
The 'retrial' method's applicability as one sentence; empty when applicable.
std::vector< T > solver_mam_getprobmarg(const qn::NetworkStruct< T > &L, const MamOptions &opt, std::size_t ist, std::size_t jobclass, const mva::AvgResult< T > &avg)
Port of @@SolverMAM/getProbMarg.m: P(n jobs of class jobclass) at station ist, for n = 0....
qsys::BmapM1Result< T > solver_mam_get_mam_result(const qn::NetworkStruct< T > &L)
@@SolverMAM/getMAMResult.m: the M/G/1-type internals of a single queue.
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.
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)
FeatureSet mam_feature_set(const std::string &method)
SolverMAM.getFeatureSet, the union of its four setTrue calls: 55 MATLAB names, WIDENED for 'default'/...
void feature_gate(const std::string &solver, const FeatureSet &declared, const NetworkStruct< T > &sn, const std::string &requested_method="", const std::string &resolved_method="")
runAnalyzerChecks: refuse a model the solver does not declare, by name.
A queueing network and its refreshed NetworkStruct.
Port of matlab/src/api/sn/sn_is_discrete_time.m.
Replace every non-Markovian service and firing law by a Markovian surrogate.
The DECLARED side of the gate: one feature set per solver.
Port of solver_mam_fj.m, the fork-join route of SolverMAM.
Port of solver_mam_ldqbd_transient.m: transient queue length, utilization and throughput of a single-...
Port of solver_mam_passage_time.m: the response-time (sojourn-time) distribution of a single open que...
Port of @@SolverMAM/getProb.m and @@SolverMAM/getProbMarg.m: the joint (level, phase) and marginal qu...
Transient analysis of a single-class open queue by the Laplace-domain transient QBD plus numerical in...
The SolverMVA class surface: @@SolverMVA/runAnalyzer.m and the gates around it.
Which laws the model carries, and why it was refused when it was.
How the caller may override the automatic decision.
std::string timescale
"auto", "discrete" or "continuous".
double slotlength
Slot length in model time units.
options.config.nonmkv and friends.
std::size_t order
nonmkvorder, the phase budget
PhFit phfit
which surrogate family
bool preserve_det
Leave Det alone for the exact MAP/D/c branch, options.config.preserveDet.
static constexpr double FineTol
The options SolverMAM reads.
What the MAM dispatch returns: the metrics plus the algorithm that ran.
std::string actualmethod
The concrete algorithm, as the reference's actualmethod.
mva::MvaSolution< T > sol
The joint (level, phase) table getProb returns: rows levels, cols phases.
One class's response-time CDF, the reference's RD{station, class} = [F, X].
What getTranAvg returns: queue length, utilization and throughput curves.
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
Class-level results, the [Q,U,R,T,C,X] of the MATLAB analyzers.
Everything qsys_bmapm1 returns, mirroring the MATLAB result struct.