5#ifndef LINE_SOLVERS_NC_SOLVER_NC_RUNNER_H
6#define LINE_SOLVERS_NC_SOLVER_NC_RUNNER_H
90 return ::line::method_registry::methods(
"NC");
103 std::vector<std::string> toks;
104 for (
char ch : method) {
105 if (ch ==
'.' || ch ==
'/') {
109 tok +=
static_cast<char>(std::tolower(
static_cast<unsigned char>(ch)));
113 for (
const std::string& t : toks)
114 if (t ==
"mci" || t ==
"imci" || t ==
"ls" || t ==
"sampling" || t ==
"is" ||
140 if (std::find(valid.begin(), valid.end(), method) != valid.end())
return;
169bool multiserver_to_lld(qn::NetworkStruct<T>& sn) {
171 for (
const qn::JobClass& c : sn.classes) {
172 if (std::isinf(c.population))
return false;
175 const std::size_t n =
static_cast<std::size_t
>(std::llround(Nt));
176 if (n < 1)
return false;
177 for (std::size_t i = 0; i < sn.nstations; ++i) {
178 std::vector<T> lld(n, num_traits<T>::from_int(1));
179 const double c = sn.stations[i].nservers;
180 if (std::isfinite(c) && c > 1.0)
181 for (std::size_t k = 1; k <= n; ++k)
183 num_traits<T>::from_double(std::min<double>(
static_cast<double>(k), c));
184 sn.stations[i].lldscaling = lld;
201inline std::string nc_multiserver_policy(
const std::string& requested,
202 std::string* warning =
nullptr) {
203 if (requested.empty() || requested ==
"default")
return "default";
204 if (requested ==
"seidmann")
return "seidmann";
205 if (requested ==
"lld" || requested ==
"exact" || requested ==
"loaddep" ||
206 requested ==
"load-dependent")
208 if (warning !=
nullptr)
209 *warning =
"SolverNC does not implement config.multiserver='" + requested +
210 "' (it is a SolverMVA approximation); using 'default'. SolverNC accepts "
211 "'default', 'seidmann' and 'lld'.";
220double nc_population_lattice(
const qn::NetworkStruct<T>& sn) {
221 double lattice = 1.0;
222 if (!sn.chains.empty()) {
224 for (std::size_t c = 0; c < sn.chains.size(); ++c) {
226 for (std::size_t r = 0; r < sn.nclasses && r < sn.chains[c].size(); ++r)
227 if (sn.chains[c][r]) {
228 const double v = sn.classes[r].population;
229 if (std::isfinite(v)) popc += v;
231 lattice *= (1.0 + popc);
234 for (
const qn::JobClass& c : sn.classes)
235 if (std::isfinite(c.population)) lattice *= (1.0 + c.population);
272 if (
sn.has_open_classes())
return true;
273 const std::size_t M =
sn.nstations, C =
sn.nchains;
274 const std::vector<double> Nchain = detail::chain_population(
sn);
276 for (std::size_t c = 0; c < C; ++c)
277 if (std::isfinite(Nchain[c])) NtD += Nchain[c];
278 const std::size_t Nt =
static_cast<std::size_t
>(std::llround(NtD));
279 if (Nt < 1)
return true;
283 std::vector<double> Ztot(C, 0.0);
284 for (std::size_t i = 0; i < M; ++i) {
285 const double nserv =
sn.stations[i].nservers;
286 for (std::size_t c = 0; c < C; ++c) {
288 if (std::isinf(nserv))
290 else if (seidmann && nserv > 1.0)
291 Ztot[c] += L * (nserv - 1.0) / nserv;
294 for (std::size_t c = 0; c < C; ++c)
295 if (Nchain[c] > 0.0 && !(Ztot[c] > 0.0))
298 for (std::size_t i = 0; i < M; ++i) {
299 const double nserv =
sn.stations[i].nservers;
300 if (std::isinf(nserv))
continue;
301 const std::vector<T>& lld =
sn.stations[i].lldscaling;
304 const double lscale = (seidmann && nserv > 1.0) ? 1.0 / nserv : 1.0;
307 else if (!lld.empty())
309 else if (nserv > 1.0)
310 muK = std::min(
static_cast<double>(Nt), nserv);
313 if (!(muK > 0.0) || !std::isfinite(muK))
return false;
315 for (std::size_t c = 0; c < C; ++c)
318 if (!(1.0 - lambda / muK > 0.0))
return false;
335 const std::size_t M =
sn.nstations, C =
sn.nchains;
336 const std::vector<double> Nchain = detail::chain_population(
sn);
337 bool any_closed =
false;
338 std::vector<bool> closed(C,
false);
339 for (std::size_t c = 0; c < C; ++c) {
340 closed[c] = std::isfinite(Nchain[c]) && Nchain[c] > 0.0;
341 if (closed[c]) any_closed =
true;
343 if (!any_closed)
return 0;
347 for (std::size_t i = 0; i < M; ++i) {
348 if (std::isinf(
sn.stations[i].nservers))
continue;
349 for (std::size_t c = 0; c < C; ++c)
402 bool slotted =
false,
bool for_report =
true) {
403 const std::string m = method.empty() ? std::string(
"default") : method;
408 if (slotted)
return "";
422 if (m !=
"default" && m !=
"morrison")
423 return "SolverNC: method '" + m +
424 "' cannot represent the DPS weights of a discriminatory processor-sharing "
425 "station; it would return the egalitarian-PS network. Use method 'default' or "
426 "'morrison' (npfqn_dps_morrison), SolverMVA, SolverFLD or SolverCTMC.";
433 return "SolverNC analyzes a discriminatory processor-sharing station only in the shape "
434 "Morrison's expansion is derived for: a CLOSED network of exactly two stations, one "
435 "infinite-server (think) station and one single-server DPS station, exponential "
436 "service, each class visiting the two equally often. Use SolverMVA, SolverFLD or "
437 "SolverCTMC for any other DPS model.";
443 return "SolverNC: method 'morrison' is the heavy-usage expansion of a CLOSED network of "
444 "exactly two stations, one infinite-server (think) station and one single-server DPS "
445 "station with exponential service, which this model is not. Remove the method option "
446 "to let SolverNC choose, or use SolverMVA, SolverFLD or SolverCTMC.";
451 if (!
sn.sdr.branch.empty())
return "";
452 if (m ==
"sdr" || m ==
"sdr.mva")
453 return "SolverNC: method '" + m +
454 "' requires state-dependent routing, which this model does not declare.";
460 for (std::size_t ind = 0; ind <
sn.nodes.size(); ++ind)
462 if (m !=
"default" && m !=
"rec")
463 return "solver_nc: a stochastic Petri net is solved by the MDD-rec route; method '" +
464 m +
"' is a normalizing-constant algorithm for queueing networks. Use 'rec' "
474 if (m !=
"default" && m !=
"exact" && m !=
"is" && m !=
"sampling")
475 return "SolverNC: method '" + m +
476 "' cannot represent the rank rate mu(n) of an order-independent station; use "
477 "method 'default' or 'exact' (pfqn_ncoi), 'is', SolverMVA, or SolverCTMC.";
495 for (std::size_t ind = 0; ind <
sn.nodes.size(); ++ind)
496 if (
sn.nodes[ind].nodetype == qn::NodeType::Cache) {
497 const auto itp =
sn.nodeparam.find(ind + 1);
498 const bool has_retrieval =
499 itp !=
sn.nodeparam.end() && itp->second.retrieval_capacity > 0;
500 bool has_source =
false;
501 for (std::size_t j = 0; j <
sn.nodes.size(); ++j)
502 if (
sn.nodes[j].nodetype == qn::NodeType::Source) has_source =
true;
504 if (m !=
"default" && m !=
"exact" && m !=
"sampling" && m !=
"rayint" && m !=
"spm")
505 return "Method '" + m +
"' has no route on a Source-Cache-Sink model: "
506 "solver_nc_cache_analyzer would answer it with the SPM saddle point under "
507 "that name. Use 'default' (or 'spm'/'rayint'), 'exact' or 'sampling'.";
508 }
else if (has_retrieval && has_source) {
509 if (m !=
"default" && m !=
"exact" && m !=
"rayint")
510 return "Method '" + m +
"' has no route on a delayed-hit retrieval cache: "
511 "solver_nc_retrieval_analyzer would answer it with the exact recurrences "
512 "under that name. Use 'default', 'exact' or 'rayint'.";
513 }
else if ((m ==
"rayint" || m ==
"spm") &&
sn.nclosedjobs() > 0) {
514 return "Method '" + m +
"' names the SPM saddle point of an isolated cache; on an "
515 "integrated cache-queueing model the name is handed to the network solve, "
516 "where pfqn_nc has no arm for it. Use 'default' (SPM cache, default network) "
519 if (m ==
"exact" && !has_retrieval && itp !=
sn.nodeparam.end() &&
522 return "NC does not support exact solution of the specified cache replacement "
523 "policy; use the default (approximate) method or SolverCTMC.";
526 if (m ==
"rayint" || m ==
"spm")
527 return "SolverNC: method " + m +
528 " names the SPM saddle point of a cache and, on a retrieval model, the ray/WKB "
529 "delayed-hit expansion; this model declares no Cache node.";
534 return "SolverNC: the Finite Capacity Region holds a single infinite server but does not "
535 "apply DROP to every class; holding an arrival back (WAITQ) or blocking the server "
536 "(BAS/BBS/RSRD) keeps the job in the region while it waits, which the Erlang loss "
537 "model has no state for -- use DROP, or SolverCTMC/SolverJMT";
539 return "SolverNC: the 'erlangfp' Erlang fixed point applies only to a loss network, which "
540 "is an open model whose single Delay sits inside a Finite Capacity Region under a "
541 "DROP rule; this model declares no such region (see nc_is_lossn_model)";
543 return "SolverNC: method 'ms' is admissible only on a loss network (open model, one DROP "
544 "region holding a single Delay).";
546 return "SolverNC: method rec is the MDD-rec route, admissible on a stochastic Petri net or "
547 "on a loss network (open model, one DROP region holding a single Delay); this model "
549 if (!
sn.regions.empty())
550 return "SolverNC: this model applies a Finite Capacity Region to queueing stations, whose "
551 "aggregate population limit no normalizing-constant algorithm here enforces; only "
552 "the loss network -- one region over a single infinite server, DROP on every "
553 "class -- is solvable. Use SolverCTMC or SolverJMT, or setCapacity for a "
554 "single-station limit";
565 for (std::size_t i = 0; i <
sn.nstations; ++i)
566 if (!
sn.stations[i].lldscaling.empty() ||
567 static_cast<bool>(
sn.stations[i].cdscaling) ||
568 static_cast<bool>(
sn.stations[i].jdscaling))
569 return "SolverNC: method 'mem' is the maximum-entropy GE/GE/1/N of "
570 "solver_nc_mem, which reads the first two moments of ONE service law and "
571 "cannot apply a declared load-, class- or joint-dependent rate. Use "
572 "SolverMVA, SolverCTMC or SolverLDES";
585 if (
sn.has_open_classes()) {
586 for (std::size_t i = 0; i <
sn.nstations; ++i)
587 if (
static_cast<bool>(
sn.stations[i].cdscaling) ||
588 static_cast<bool>(
sn.stations[i].jdscaling))
589 return "SolverNC: class- or joint-dependent rates are solved by the convolution "
590 "of solver_nc_conv, Sauer's multichain recursion on the CLOSED population "
591 "lattice, which holds no position for an open chain; this model is open "
592 "or mixed. Use SolverMVA, SolverCTMC or SolverLDES";
601 bool any_cd =
false, any_multi =
false, any_lld =
false;
602 for (std::size_t i = 0; i <
sn.nstations; ++i) {
603 if (
static_cast<bool>(
sn.stations[i].cdscaling) ||
604 static_cast<bool>(
sn.stations[i].jdscaling))
606 const double c =
sn.stations[i].nservers;
607 if (std::isfinite(c) && c > 1.0) any_multi =
true;
608 if (!
sn.stations[i].lldscaling.empty()) any_lld =
true;
610 if (any_cd && (any_multi || any_lld))
611 return "SolverNC: class- or joint-dependent rates are solved by the convolution of "
612 "solver_nc_conv, which reads no server count above one and no load-dependent "
613 "rate lattice; fold the multiserver capacity into the class-dependent handle, "
614 "or use SolverMVA or SolverCTMC";
631 if ((m ==
"pana" || m ==
"panald") && !
sn.has_open_classes()) {
632 bool diverted_to_conv =
false, any_lld =
false;
633 for (std::size_t i = 0; i <
sn.nstations; ++i) {
634 if (
static_cast<bool>(
sn.stations[i].cdscaling) ||
635 static_cast<bool>(
sn.stations[i].jdscaling))
636 diverted_to_conv =
true;
637 if (!
sn.stations[i].lldscaling.empty()) any_lld =
true;
639 const bool reaches_ld_kernel = (m ==
"panald") || any_lld;
641 const std::string why =
642 "the model is not in normal usage, so the 'panald' asymptotic expansion does "
643 "not apply. Use 'exact', 'clw' or an approximate load-dependent method instead.";
645 return "SolverNC: method 'pana' reaches the load-dependent kernel on this "
646 "model, where pfqn_ncld evaluates it as 'panald', and " + why;
647 return "SolverNC: " + why;
653 if (for_report && !diverted_to_conv && !reaches_ld_kernel &&
655 return "SolverNC: the model is not in normal usage, so the 'pana' asymptotic "
656 "expansion does not apply (pfqn_panacea returns NaN and the analyzer an "
657 "empty table). Use 'exact', 'clw' or 'default' instead.";
679 if (m ==
"comom" || m ==
"comomld" || (for_report && (m ==
"mmint2" || m ==
"gleint"))) {
683 return "SolverNC: method 'comomld' is the load-dependent CoMoM recursion, and "
684 "pfqn_comomrm_ld accepts at most a single queueing station; this model has " +
685 std::to_string(nq) +
".";
687 return "SolverNC: method 'comom' is the CoMoM recursion of pfqn_comomrm, which "
688 "accepts at most a single queueing station; this model has " +
689 std::to_string(nq) +
". Use 'default' or 'ca' for an exact normalizing "
690 "constant, or SolverJMT with method 'jmva.recal'.";
691 return "SolverNC: the '" + m +
692 "' method requires a model with a delay and a single queueing station; this "
693 "model has " + std::to_string(nq) +
".";
700 for (std::size_t i = 0; i <
sn.nstations; ++i)
701 if (std::isfinite(
sn.stations[i].nservers) &&
sn.stations[i].nservers > 1.0) multi =
true;
702 if (multi &&
sn.has_open_classes())
703 return "solver_nc_analyzer: the NC solver cannot provide exact solutions for open "
704 "or mixed multiserver queueing networks. Remove the 'exact' option";
707 if (multi && detail::has_node_type(
sn, qn::NodeType::Fork))
708 return "SolverNC: NC solver cannot provide exact solutions for a fork-join model with a "
709 "multiserver station: the fork-join transformation carries the parallelism as "
710 "open auxiliary classes, so the inner model is mixed. Remove the 'exact' option.";
717 bool scaling =
false, multiserver =
false, fractional =
false;
718 for (std::size_t i = 0; i <
sn.nstations; ++i) {
719 const auto& st =
sn.stations[i];
720 if (!st.lldscaling.empty() ||
static_cast<bool>(st.cdscaling) ||
721 static_cast<bool>(st.jdscaling))
723 if (std::isfinite(st.nservers) && st.nservers > 1.0) multiserver =
true;
729 if ((scaling || multiserver) && fractional)
730 return "SolverNC: NC load-dependent solver cannot provide exact solutions for "
731 "fractional populations.";
760 if (opt_in.
method ==
"cftp" || opt_in.
method ==
"cftp.approx") {
768 "SolverNC(cftp): the cftp methods draw random states and form the station "
769 "balance functions in the log domain, neither of which exists in exact rational "
786 if (st.
sched == qn::SchedStrategy::OI || st.
sched == qn::SchedStrategy::PAS) oi =
true;
789 "SolverNC: method '" + opt_in.
method +
"' requires a product-form solution; use "
790 "SolverCTMC for an exact answer, or 'comom', which applies Seidmann's "
791 "approximation, for an approximate one");
806 const std::string refusal =
853 bool mem_blocking =
false;
854 if (
opt.method ==
"mem") {
858 const bool mm1k_closed_form =
869 std::vector<T> lam(
tr.V.classes.size() + 1,
915 const std::size_t src = mva::detail::station_of_type(L, qn::NodeType::Source);
916 const std::size_t q = mva::detail::station_of_type(L, qn::NodeType::Queue);
918 const T Vq = L.
visits[0](qstateful - 1, 0);
919 const T lambda = T(L.
rates(src - 1, 0) * Vq);
920 const T mu = L.
rates(q - 1, 0);
921 const T rho = T(lambda / mu);
922 const double Kcap = L.
cap[q - 1];
923 const unsigned Kint =
static_cast<unsigned>(std::llround(Kcap));
925 const T Tq = T(lambda * (one - Ploss));
934 Lsys = T(rho / (one - rho) - Kp1 * rKp1 / (one - rKp1));
942 ls.
X.assign(1, zero);
943 ls.
C.assign(1, zero);
947 ls.
R(q - 1, 0) = T(Lsys / Tq);
948 ls.
Q(q - 1, 0) = Lsys;
949 ls.
U(q - 1, 0) = T(Tq / mu);
950 ls.
Tp(q - 1, 0) = Tq;
951 ls.
Tp(src - 1, 0) = lambda;
953 ls.
C[0] = T(ls.
R(q - 1, 0) * Vq);
975 for (std::size_t ind = 0; ind < L.
nodes.size(); ++ind)
979 bool multiserver =
false;
989 std::string ms_warning;
990 const std::string ms_policy =
991 detail::nc_multiserver_policy(
opt.multiserver, &ms_warning);
993 if (
opt.method ==
"default") {
997 if (L.
nstations == 2 && !detail::has_node_type(L, qn::NodeType::Cache) &&
998 detail::has_node_type(L, qn::NodeType::Delay) && multiserver) {
1000 if (detail::multiserver_to_lld(L)) anyLld =
true;
1002 opt.method =
"comom";
1004 }
else if (ms_policy ==
"lld" && multiserver && !anyLld && L.
has_product_form() &&
1005 detail::nc_population_lattice(L) <= 6000.0) {
1011 if (detail::multiserver_to_lld(L)) anyLld =
true;
1013 }
else if (
opt.method ==
"exact" ||
opt.method ==
"is" ||
opt.method ==
"panald") {
1034 "SolverNC: the '" +
opt.method +
1035 "' method requires the model to have a product-form solution, and this model "
1043 if (!anyLld && multiserver && ms_policy !=
"seidmann") {
1044 if (detail::multiserver_to_lld(L)) anyLld =
true;
1054 if (detail::has_node_type(L, qn::NodeType::Source)) {
1075 std::vector<T>(), std::vector<T>(),
1088 for (std::size_t ci = 0; ci < res.
cache.caches.size() && ci < cr.
itemprob.size(); ++ci)
1090 for (std::size_t ci = 0; ci < res.
cache.caches.size() && ci < cr.
listcost.size(); ++ci)
1119 if (anyLld || nc::detail::has_scaling(L)) {
1121 }
else if (
opt.method ==
"rd" ||
opt.method ==
"nrp" ||
opt.method ==
"nrl" ||
1122 opt.method ==
"nre" ||
opt.method ==
"comomld" ||
opt.method ==
"panald") {
1130 if (!ms_warning.empty())
1143 const std::string& origmethod);
1157 const std::string& origmethod) {
1163 std::vector<std::vector<bool>> mask(M, std::vector<bool>(K,
false));
1164 for (std::size_t i = 0; i < M; ++i)
1165 for (std::size_t k = 0; k < K; ++k)
1167 std::vector<std::vector<bool>> srcmask(M, std::vector<bool>(K,
false));
1168 for (std::size_t i = 0; i < M; ++i)
1169 if (L.
stations[i].nodetype == qn::NodeType::Source)
1170 for (std::size_t k = 0; k < K; ++k) srcmask[i][k] =
true;
1191 std::string satwarn;
1200 out.
actualmethod = (origmethod ==
"default" && !actualmethod.empty() &&
1201 actualmethod !=
"default")
1202 ?
"default/" + actualmethod
1210 "SolverNC does not handle immediate feedback (immfeed); the solver will treat "
1211 "self-loops as class-switching with re-queueing.";
1217 if (!satwarn.empty())
1231 if (std::isfinite(lg))
What a solver observed about the Cache nodes of a model.
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
bool has_immediate_feedback() const
Whether immediate feedback is EFFECTIVE anywhere in the model.
std::size_t stateful_of_station(std::size_t st) const
std::vector< double > cap
sn.cap and sn.classcap: the total and per-class buffers.
std::vector< Station< T > > stations
stations[k-1] is the k-th station
Matrix< T > rates
(nstations x nclasses) service rates and SCVs, with a PARALLEL disabled flag instead of MATLAB's NaN ...
std::vector< NodeDef > nodes
every node, in creation order
std::vector< Matrix< T > > visits
(nchains) each (nstateful x nclasses)
bool has_product_form() const
sn_has_product_form, conjunct for conjunct.
static void step(const char *fmt,...)
Write one progress line.
The exception types the port throws.
The fork-join fixed point that drives one inner MVA solve.
The Heidelberger-Trivedi fork-join transform, options.config.fork_join='ht'.
The fork-join transform SolverMVA applies before solving a layer that contains a Fork.
Running progress log of a LINE solver run (the "solver console").
The method names of each solver, in listing order.
bool sn_is_mm1k_loss(const qn::NetworkStruct< T > &sn)
sn_is_mm1k_loss: the three-node Source/Queue/Sink model of an M/M/1/K with loss, the shape MVA answer...
NodeType
Node kinds, with the values of MATLAB NodeType.
@ FIFO
first in, first out
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.
bool cap_unstable_open_stations(const qn::NetworkStruct< T > &L, Matrix< T > &QN, Matrix< T > &UN, Matrix< T > &RN, const Matrix< T > &TN)
The saturated open-station rule of @@NetworkSolver/getAvg.m:221-308.
void apply_analyzer_arvr(Matrix< T > &AN, const Matrix< T > &supplied)
Overwrite the routing-derived arrival rates with those an analyzer supplied (MvaSolution::AN,...
const char * unstable_open_warning()
The warning getAvg.m raises when cap_unstable_open_stations() fires.
FjMmt< T > fj_fork_join_transform(const qn::NetworkStruct< T > &L, const std::string &method)
options.config.fork_join -> the transform it names.
MvaSolution< T > fj_fixed_point(const qn::NetworkStruct< T > &L, FjMmt< T > &tr, std::vector< T > &lam, const MvaOptions &opt, InnerSolve inner, std::string *warning=nullptr)
Drive the fork-join fixed point of a transformed model to convergence.
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...
ChainDemands< T > sn_get_demands_chain(const qn::NetworkStruct< T > &L)
Port of sn_get_demands_chain.
NcCftpSolution< T > solver_nc_cftp(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt, const NcCftpOptions &cftpopt)
Solve with the cftp / cftp.approx method.
mva::AvgResult< T > solver_nc_run_analyzer(const qn::NetworkStruct< T > &L_in, const NcSolverOptions &opt_in)
bool nc_is_cacheqn(const qn::NetworkStruct< T > &sn)
True when the model has a Cache node and is not the Source-Cache-Sink shape.
bool nc_is_oi_model(const qn::NetworkStruct< T > &sn)
Port of nc_is_oi_model.m: a closed network with at least one OI station and nothing but BCMP product-...
NcSolution< T > solver_nc_dt(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Exact discrete-time analysis of sn.
NcSpnSolution< T > solver_nc_spn_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Analyse a product-form stochastic Petri net.
NcSolution< T > solver_nc_dps_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Analyzes the closed think+DPS network.
MemSupport solver_nc_mem_supports(const qn::NetworkStruct< T > &sn)
Port of solver_nc_mem_supports.m.
NcCacheSolution< T > solver_nc_cache_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Port of solver_nc_cache_analyzer.m.
bool nc_is_normal_usage(const qn::NetworkStruct< T > &sn, bool seidmann=false)
Is the closed model in NORMAL USAGE, the domain of the Mitra-McKenna PANACEA asymptotic expansion (J.
NcSolution< T > solver_nc_cftp_solution(const NcCftpSolution< T > &s)
A cftp solve in the shape every other SolverNC analyzer returns, so the runner's metric filter applie...
bool nc_is_lossn_model(const qn::NetworkStruct< T > &sn)
True when the model is a loss network: the shape above, with EVERY class dropped at the region.
bool nc_is_pas_model(const qn::NetworkStruct< T > &sn)
Port of nc_is_pas_model.m: a closed two-station OI / P&S tandem.
NcSolution< T > solver_nc_oi_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Port of solver_nc_oi_analyzer.m.
double solver_nc_lognormconst(const qn::NetworkStruct< T > &L, const NcSolverOptions &opt)
Port of @@SolverNC/getProbNormConstAggr.m: the log normalizing constant.
std::string resolve_method(const qn::NetworkStruct< T > &, const std::string &method)
Port of SolverNC.resolveMethod: default is NOT resolved ahead of the run.
NcCacheqnRetrievalSolution< T > solver_nc_cacheqn_retrieval_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Port of solver_nc_cacheqn_retrieval_analyzer.m.
void check_method(const std::string &method)
Port of runAnalyzerChecks' method gate: an unlisted method is refused.
std::vector< std::string > list_valid_methods()
Port of SolverNC.listValidMethods.
std::size_t nc_closed_queueing_stations(const qn::NetworkStruct< T > &sn)
How many queueing (non-infinite-server) stations carry demand from a CLOSED chain?
NcRetrievalSolution< T > solver_nc_retrieval_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Port of solver_nc_retrieval_analyzer.m.
NcSolution< T > solver_nc_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Port of solver_nc_analyzer.m.
bool is_stochastic_method(const std::string &method)
Port of SolverNC.isStochasticMethod.
NcSolution< T > solver_nc_solve(const qn::NetworkStruct< T > &L_in, const NcSolverOptions &opt_in)
The gates, the multiserver conversion and the dispatch of @@SolverNC/runAnalyzer.m,...
bool nc_has_lossn_shape(const qn::NetworkStruct< T > &sn)
True when the model has the SHAPE of a loss network – open, one region, one member station,...
NcCacheqnSolution< T > solver_nc_cacheqn_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Port of solver_nc_cacheqn_analyzer.m.
NcSolution< T > solver_ncld_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Port of solver_ncld_analyzer.m: the load-dependent analyzer, which is solver_ncld plus the same fract...
bool sn_has_dps(const qn::NetworkStruct< T > &sn)
True when any station of the network is scheduled DPS.
bool nc_has_retrieval(const qn::NetworkStruct< T > &sn)
True when the model's Cache carries a delayed-hit retrieval system.
NcLossnSolution< T > solver_nc_lossn_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Port of solver_nc_lossn_analyzer.m.
bool nc_is_noreentrant_cache(const qn::NetworkStruct< T > &sn)
True when the model is exactly a Source, a Cache and a Sink.
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?
mva::AvgResult< T > solver_nc_avg_table(const qn::NetworkStruct< T > &L_in, const NcSolution< T > &d, const std::string &origmethod)
Port of @@SolverNC/runAnalyzer.m for the lang='matlab' path: solve, then apply the metric filter @@Ne...
std::string solver_nc_cftp_supports(const qn::NetworkStruct< T > &sn)
The cftp model-class gate as a public predicate.
bool nc_is_dps_model(const qn::NetworkStruct< T > &sn)
True when the model is the closed two-station network Morrison's expansion is derived for: one infini...
NcSolution< T > nc_dispatch(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Port of @@SolverNC/ncDispatch.m: the inner solve of the fork-join fixed point, which is the load-depe...
FeatureSet nc_feature_set(const std::string &method)
SolverNC.getFeatureSet, 48 names, transcribed unchanged.
void check_binding_capacity(const std::string &solver, const NetworkStruct< T > &sn)
NetworkSolver.checkBindingCapacity (NetworkSolver.m:1172-1228): the shared structural gate for finite...
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.
Mm1kLossResult< T > qsys_mm1k_loss(const T &lambda, const T &mu, unsigned K)
Blocking probability of the M/M/1/K queue.
CacheMetrics< T > cache_metrics_of(const qn::NetworkStruct< T > &sn, const std::vector< T > &hitprob, const std::vector< T > &missprob, const std::vector< T > &delayedprob, const std::vector< T > &latency, const Matrix< T > &hitproblist, const Matrix< T > &itemprob, const std::vector< T > &listcost)
Assemble CacheMetrics from what a cache analyzer returned.
CacheMetrics< T > cache_metrics_of_matrix(const qn::NetworkStruct< T > &sn, const Matrix< T > &hitprob, const Matrix< T > &missprob)
The same, for the integrated caching-queueing branch, whose hit and miss probabilities are (ncaches x...
Conservation laws of a layered queueing network, enumerated from its structure.
T num_pow_int(const T &base, unsigned e)
Integer power, valid in any field (no transcendental requirement).
Port of solver_nc_analyzer.m, solver_ncld_analyzer.m and @@SolverNC/ncDispatch.m: one inner solve,...
Controls and result shape shared by the normalizing-constant analyzers.
A queueing network and its refreshed NetworkStruct.
Blocking probability of the M/M/1/K queue.
Chain aggregation and de-aggregation.
Ports of the sn_has_* / sn_is_* predicate family of matlab/src/api/sn.
The DECLARED side of the gate: one feature set per solver.
The SolverMVA class surface: @@SolverMVA/runAnalyzer.m and the gates around it.
Port of solver_nc_cache_analyzer.m: the NON-REENTRANT cache, a model that is exactly a Source,...
Port of solver_nc_cacheqn_analyzer.m: the INTEGRATED caching-queueing network, where a Cache sits ins...
Port of solver_nc_cacheqn_retrieval_analyzer.m: a CLOSED integrated cache-queueing model whose Cache ...
The cftp and cftp.approx methods of SolverNC: stationary analysis of a closed single-class product-fo...
Heavy-usage asymptotic analysis of the closed two-station network with one think (infinite-server) st...
Port of solver_nc_lossn_analyzer.m: the open LOSS NETWORK, which is a Source, ONE multiclass Delay si...
Port of solver_nc_mem.m and solver_nc_mem_supports.m: the Maximum Entropy Method of Kouvatsos (1994).
Order-independent (OI) and pass-and-swap (P&S) normalizing-constant analysis.
Port of solver_nc_retrieval_analyzer.m: the OPEN delayed-hit (retrieval-system) cache.
Stationary analysis of a PRODUCT-FORM stochastic Petri net by MDD-rec.
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
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
solvers::FjMetrics< T > fj
self.result.FJ: the fork-join section metrics FJQLen, FJRespT and FJTput, filled by the solvers the f...
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 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
solvers::CacheMetrics< T > cache
What the cache branches observed, EMPTY on a model with no Cache node and on every solver that does n...
Matrix< T > AN
arrival rate
The chain-level view of a layer, as sn_get_demands_chain returns it.
Matrix< T > Lchain
(M x C) demand
The transformed layer and the bookkeeping the fixed point needs to drive it and to merge its results ...
The options SolverMVA reads.
bool base_has_fork
Whether the model this solve came from has a Fork, which the model handed to the analyzer no longer d...
std::string fork_join
options.config.fork_join: which fork-join arm the fixed point takes.
Class-level results, the [Q,U,R,T,C,X] of the MATLAB analyzers.
double lG
log of the normalizing constant, the reference's lG.
Matrix< T > AN
Analyzer-supplied station arrival rates (M x K), NaN where the runner derives them from the routing; ...
solvers::FjMetrics< T > fj
Fork-join section metrics set by the fork-join fixed point (fj_driver.h); empty otherwise.
static constexpr double FineTol
The verdict of solver_nc_mem_supports.
bool blocking
the model carries a binding finite station buffer
What the cache analyzer returns beyond the usual metric table.
Matrix< T > hitproblist
(u x h) access-weighted per-list hit probability, NaN if not exact
std::vector< T > missprob
(u) per-class miss and hit PROBABILITIES, missrate divided by the read class's arrival rate and its c...
Matrix< T > itemprob
(n x h+1) the same from the EXACT recursion, NaN above 10 items
std::vector< T > listcost
(h) mean storage cost held by each list, EMPTY without item sizes
What the closed delayed-hit analyzer returns.
std::vector< T > delayedprob
(K) zero on this path, by the reference's convention
std::vector< T > missprob
(K) the delayed fraction is folded in here
std::vector< T > hitprob
(K) P(item cached)
std::vector< T > latency
(K) NaN: not computed on this path
Matrix< T > hitproblist
(K x h) NaN: not computed on this path
What the integrated analyzer returns: the metrics plus the converged split.
Matrix< T > hitprob
(ncaches x nclasses) converged hit probability
Matrix< T > missprob
(ncaches x nclasses)
qn::NetworkStruct< T > refreshed
The struct whose cache self-switch carries the CONVERGED split rather than the offered one,...
std::vector< std::vector< T > > listcost
per cache, (h) mean storage cost per list; EMPTY without item sizes
std::vector< Matrix< T > > itemprob
per cache, (n x h+1); EMPTY = not computed
What the delayed-hit analyzer returns beyond the metric table.
Matrix< T > itemprob
(n x h+1) column 0 = miss, 1.. = per list
std::vector< T > missprob
(K)
std::vector< T > hitprob
(K) TRUE hit fraction, NaN off the read class
Matrix< T > hitproblist
(K x h) per-list hit fraction
std::vector< T > delayedprob
(K) delayed-hit fraction
std::vector< T > latency
(K) NaN: the latency belongs to SolverMVA
The [Q,U,R,T,C,X,lG] of the reference, plus the algorithm that ran.
std::vector< T > listcost
(h) mean storage cost held by each cache list, K_j = sum_i sigma_i pi_ij.
mva::MvaSolution< T > sol
std::string warning
The reference's warning text, verbatim, empty when it did not warn.
std::shared_ptr< qn::NetworkStruct< T > > refreshed_struct
Set only by the integrated cacheqn branch: the converged struct whose routing carries the ACTUAL hit/...
solvers::CacheMetrics< T > cache
What the cache branches observed, EMPTY on a model with no Cache node.
Controls, defaulting to SolverOptions('NC') in the reference.
bool base_has_fork
Whether the model this solve came from has a Fork, which the model handed to the analyzer no longer d...
bool slotted
options.config.slotted.
One job class of the network.
double population
infinite for an open class
One station of the network.
double nservers
may be infinite (a Delay, or an inf-scheduled task)
std::vector< T > lldscaling
sn.lldscaling for this station: the multiplier at population 1, 2, ... Empty when the station is not ...