5#ifndef LINE_SOLVERS_CTMC_SOLVER_CTMC_CFTP_H
6#define LINE_SOLVERS_CTMC_SOLVER_CTMC_CFTP_H
73 unsigned long seed = 23000;
91namespace cftp_detail {
95 if (method ==
"cftp" || method ==
"cftp.exact" || method.empty())
98 throw InputError(
"SolverCTMC(cftp): unknown cftp variant '" + method +
99 "'. Use 'cftp' or 'cftp.approx'");
120std::string cftp_supports_reason(
const NetworkStruct<T>&
sn) {
122 const std::size_t M =
sn.nstations;
123 if (
sn.nclasses != 1)
125 "SolverCTMC(cftp): the cftp method supports single-class models only, this model has " +
126 std::to_string(
sn.nclasses) +
" classes");
127 const std::vector<double> njobs =
sn.njobs();
128 if (!std::isfinite(njobs[0]) || njobs[0] < 1.0)
129 return (
"SolverCTMC(cftp): the cftp method supports closed models only, "
130 "with a finite positive population");
132 return (
"SolverCTMC(cftp): the cftp method requires at least two stations");
133 for (std::size_t ind = 0; ind <
sn.nodes.size(); ++ind) {
135 if (t != NodeType::Queue && t != NodeType::Delay && t != NodeType::Router)
137 "SolverCTMC(cftp): the cftp method supports Queue, Delay and Router nodes only, "
139 std::to_string(ind + 1) +
" is of a different type");
141 for (std::size_t i = 0; i < M; ++i) {
143 if (!(s == SchedStrategy::INF || s == SchedStrategy::PS || s == SchedStrategy::FCFS ||
144 s == SchedStrategy::SIRO || s == SchedStrategy::LCFSPR))
146 "SolverCTMC(cftp): the cftp method requires a product-form scheduling strategy "
147 "(INF, PS, FCFS, SIRO, LCFSPR) at station " +
148 std::to_string(i + 1));
149 if (sn.phases_of(i + 1, 1) > 1)
151 "SolverCTMC(cftp): the cftp method requires exponential service times, station " +
152 std::to_string(i + 1) +
" has " + std::to_string(sn.phases_of(i + 1, 1)) +
154 if (std::isfinite(sn.cap[i]) && sn.cap[i] < njobs[0])
156 "SolverCTMC(cftp): the cftp method requires infinite buffers, station " +
157 std::to_string(i + 1) +
" has capacity " + std::to_string(sn.cap[i]));
158 if (!(sn.rates(i, 0) > zero))
159 return (
"SolverCTMC(cftp): the cftp method requires a finite positive "
160 "service rate at station " +
161 std::to_string(i + 1));
162 if (!sn.stations[i].lldscaling.empty() || sn.stations[i].cdscaling ||
163 sn.stations[i].jdscaling)
164 return (
"SolverCTMC(cftp): the cftp method does not support "
165 "load-dependent, class-dependent or joint-dependent service "
168 if (!sn.regions.empty())
170 "SolverCTMC(cftp): the cftp method does not support finite capacity regions");
171 for (std::size_t ind = 0; ind < sn.nodes.size(); ++ind)
172 for (std::size_t r = 0; r < sn.nodes[ind].routing.size(); ++r) {
177 "SolverCTMC(cftp): the cftp method requires Markovian routing (PROB, RAND), "
179 std::to_string(ind + 1) +
" uses a state-dependent strategy");
181 return std::string();
191void cftp_assert(
const NetworkStruct<T>& sn) {
192 const std::string reason = cftp_supports_reason(sn);
211 return cftp_detail::cftp_supports_reason(
sn);
225 "solver_ctmc_cftp draws random states and forms the station balance functions "
226 "in the log domain, neither of which exists in exact rational arithmetic");
228 const std::size_t M =
sn.nstations, R =
sn.nclasses;
231 cftp_detail::cftp_assert(
sn);
233 throw InputError(
"SolverCTMC(cftp): the cftp method requires a finite positive number of "
234 "samples; pass --samples");
237 std::vector<T> L(M, zero);
238 for (std::size_t i = 0; i < M; ++i) L[i] = ch.
Lchain(i, 0);
239 const int N =
static_cast<int>(ch.
Nchain[0]);
240 std::vector<int> S(M, 1);
241 for (std::size_t i = 0; i < M; ++i)
242 S[i] =
sn.stations[i].sched == SchedStrategy::INF
244 :
static_cast<int>(
sn.stations[i].nservers);
254 o.
avg.XN.assign(R, zero);
255 o.
avg.CN.assign(R, zero);
259 std::vector<T> busy(M, zero);
260 for (std::size_t i = 0; i < M; ++i) {
262 for (std::size_t r = 0; r < cftpopt.
samples; ++r) {
263 const int n = s.
X(r, i);
273 if (o.
avg.XN[0] > zero)
276 for (std::size_t i = 0; i < M; ++i) {
277 o.
avg.QN(i, 0) = s.
Q[i];
279 o.
avg.UN(i, 0) =
sn.stations[i].sched == SchedStrategy::INF
282 if (o.
avg.TN(i, 0) > zero) o.
avg.RN(i, 0) = T(o.
avg.QN(i, 0) / o.
avg.TN(i, 0));
287 std::map<std::vector<int>, std::size_t> counts;
288 for (std::size_t r = 0; r < cftpopt.
samples; ++r) {
289 std::vector<int> row(M, 0);
290 for (std::size_t i = 0; i < M; ++i) row[i] = s.
X(r, i);
293 for (std::map<std::vector<int>, std::size_t>::const_iterator it = counts.begin();
294 it != counts.end(); ++it) {
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Dense matrix and non-owning view.
mva::AvgResult< T > solver_ctmc_avg_table(const NetworkStruct< T > &sn, const CtmcSolution< T > &d, const std::string &method)
Port of @@SolverCTMC/runAnalyzer.m's result assembly: solve, then apply the metric filter @@NetworkSo...
std::string solver_ctmc_cftp_supports(const NetworkStruct< T > &sn)
The cftp model-class gate as a public predicate.
CtmcCftpSolution< T > solver_ctmc_cftp(const NetworkStruct< T > &sn, const CtmcOptions &opt, const CtmcCftpOptions &cftpopt)
Solve with the cftp / cftp.approx method.
mva::AvgResult< T > solver_ctmc_cftp_run_analyzer(const NetworkStruct< T > &sn, const CtmcOptions &opt, const CtmcCftpOptions &cftpopt)
Solve with cftp and format, for a caller with no use for the sampled states.
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
RoutingStrategy
Routing strategies, with the values of MATLAB RoutingStrategy.
NodeType
Node kinds, with the values of MATLAB NodeType.
ChainDemands< T > sn_get_demands_chain(const qn::NetworkStruct< T > &L)
Port of sn_get_demands_chain.
std::mt19937_64 McRng
The generator type every Monte Carlo entry point in this tree accepts.
constexpr int cftp_inf_servers
Sentinel for an infinite-server (delay) station, the reference's S = Inf.
CftpMethod
Which sampler to run.
@ Cftp
exact, monotone coupling from the past
@ Approx
the rapidly-mixing approximate sampler M_A
CftpResult< T > pfqn_cftp(const std::vector< T > &L, int N, const std::vector< int > &S, std::size_t nsamples, CftpMethod method, McRng &rng)
Perfect stationary state sampling for closed single-class multiserver product-form networks,...
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
Perfect stationary state sampling for closed single-class multiserver product-form networks,...
Randomness scaffolding shared by the Monte Carlo normalizing-constant estimators (pfqn_mci,...
Chain aggregation and de-aggregation.
Port of solver_ctmc.m: the infinitesimal generator of a queueing network, assembled from the enumerat...
Port of solver_ctmc_analyzer.m and the parts of @@SolverCTMC/runAnalyzer.m that surround one solve: t...
The mean performance metrics a stationary vector maps to.
The knobs of one perfect-sampling run.
std::size_t samples
Number of iid stationary draws; the reference has no default here.
unsigned long seed
Stream seed, so a row is reproducible within this port.
What one cftp solve produces beside the means.
std::vector< std::vector< int > > distinct_states
The distinct sampled states, aligned with paggr.
std::vector< T > paggr
Empirical probability of each distinct sampled state.
Matrix< int > states
(samples x stations) the sampled states, one draw per row.
std::vector< long > horizon
(samples) per-draw coalescence horizon, or the mixing steps of M_A.
The SolverCTMC knobs this port honours.
Everything one CTMC solve produces.
The metrics getAvg returns, after filtering.
The chain-level view of a layer, as sn_get_demands_chain returns it.
std::vector< std::size_t > refstatchain
(C) 1-based reference station
std::vector< double > Nchain
(C) population, infinite for an open chain
Matrix< T > STchain
(M x C) mean service time
Matrix< T > Lchain
(M x C) demand
Matrix< T > Vchain
(M x C) visits
Return value of pfqn_cftp, mirroring [Q, X, T].
Matrix< int > X
(nsamples x M) sampled states, rows sum to K
std::vector< T > Q
(M) empirical mean queue length
std::vector< long > horizon
(nsamples) coalescence horizon or step count