5#ifndef LINE_SOLVERS_MAM_SOLVER_MAM_DECMMAP_H
6#define LINE_SOLVERS_MAM_SOLVER_MAM_DECMMAP_H
75namespace decmmap_detail {
77using lang::GlobalConstants;
82void check_disciplines(
const qn::NetworkStruct<T>& L) {
83 for (std::size_t i = 0; i < L.nstations; ++i) {
89 std::string(
"SolverMAM: the dec.mmap method has no branch for ") +
91 "'. solver_mam.m warns and returns EMPTY metrics with a cleared method name for such a "
92 "model, which is no answer at all; note that INF is not in its list either, so a model "
93 "carrying a Delay belongs to 'dec.source' or 'dec.source.mmap'");
110 "solver_mam_decmmap: the departure-process fixed point stops on a tolerance, "
111 "MMAP[K]/PH[K]/1 runs the ADDA doubling iteration and the ETAQA departure process "
112 "needs transcendental arithmetic; rerun with --arith double or --arith real");
114 using namespace decmmap_detail;
115 using namespace basic_mmap_detail;
116 using basic_detail::station_visits;
117 using basic_detail::truncate_renorm;
123 check_disciplines(L);
126 "SolverMAM: the dec.mmap method solves open models only. solver_mam.m warns and "
127 "returns the ZERO matrices it initialised for anything else, which reports an empty "
128 "network rather than refusing; use 'dec.source', 'dec.source.mmap' or 'mna'");
133 std::vector<T> lambda(K, zero);
134 for (std::size_t c = 0; c < C; ++c) {
135 if (L.
inchain[c].empty())
continue;
136 const std::size_t rs = L.
classes[L.
inchain[c][0] - 1].refstat - 1;
138 for (std::size_t k : L.
inchain[c]) {
139 if (L.
disabled[rs][k - 1])
continue;
141 tot += L.
rates(rs, k - 1);
143 for (std::size_t k : L.
inchain[c]) lambda[k - 1] = tot;
147 const MmapPhTable<T> ph = mmap_ph_table(L);
150 Matrix<T> QN(M, K, zero), UN(M, K, zero), RN(M, K, zero), TN(M, K, zero);
151 for (std::size_t i = 0; i < M; ++i)
152 if (L.
stations[i].sched == SchedStrategy::EXT)
153 for (std::size_t r = 0; r < K; ++r)
160 auto sweep = [&](
const std::vector<T>&,
161 std::size_t itnum) -> std::pair<std::vector<T>, std::vector<T>> {
163 for (std::size_t i = 0; i < M; ++i)
164 for (std::size_t r = 0; r < K; ++r)
165 DEP[i][r] = (lambda[r] > zero && V(i, r) > zero)
166 ?
map_scale(ph.PH[i][r], T(one / T(lambda[r] * V(i, r))))
177 std::vector<T> xref(M * K, zero);
178 for (std::size_t i = 0; i < M; ++i)
179 for (std::size_t r = 0; r < K; ++r) xref[i * K + r] = QN(i, r);
181 for (std::size_t i = 0; i < M; ++i) {
184 const double ns = L.
stations[i].nservers;
185 bool finiteCapUsed =
false;
187 if (L.
nodes[ind].nodetype == qn::NodeType::Queue && ARV[ind].order() > 0) {
188 if (ARV[ind].order() > tcfg.
space_max) ARV[ind] = compress_arrival(ARV[ind]);
190 for (std::size_t r = 0; r < K; ++r) TN(i, r) = lam[r];
192 std::vector<PhService<T>> sl;
193 for (std::size_t r = 0; r < K; ++r) sl.push_back(ph.svc[i][r]);
195 if (sc == SchedStrategy::FCFS || sc == SchedStrategy::HOL ||
196 sc == SchedStrategy::FCFSPRPRIO) {
197 if (std::isfinite(L.
stations[i].cap)) {
198 const std::size_t capK =
199 static_cast<std::size_t
>(std::llround(L.
stations[i].cap));
200 T meanQ = zero, lossProb = zero;
204 for (std::size_t r = 0; r < K; ++r)
208 lamTot, det.
muRate,
static_cast<unsigned>(std::llround(ns)),
209 static_cast<unsigned>(capK));
213 const basic_detail::TruncRenorm<T>
tr =
214 truncate_renorm(ARV[ind], sl, capK);
216 lossProb =
tr.lossProb;
218 std::vector<T> eff(K, zero), Sact(K, zero);
220 for (std::size_t r = 0; r < K; ++r) {
223 eff[r] = T(inflow * T(one - lossProb));
230 for (std::size_t r = 0; r < K; ++r) {
231 const T c = T(eff[r] * Sact[r]);
234 const T w = T(T(meanQ / sumTN) - T(sw / sumTN));
235 Wq = (w > zero) ? w : zero;
237 for (std::size_t r = 0; r < K; ++r) {
239 UN(i, r) = T(TN(i, r) *
map_mean(ph.PH[i][r]));
240 if (TN(i, r) > zero) {
241 RN(i, r) = T(Wq + Sact[r]);
242 QN(i, r) = T(TN(i, r) * RN(i, r));
248 finiteCapUsed =
true;
254 for (std::size_t r = 0; r < K; ++r)
255 QN(i, r) = m[ARV[ind].classes() == 1 ? 0 : r];
257 }
else if (sc == SchedStrategy::PS) {
258 for (std::size_t r = 0; r < K; ++r)
259 UN(i, r) = T(TN(i, r) *
map_mean(ph.PH[i][r]));
261 for (std::size_t r = 0; r < K; ++r) usum += UN(i, r);
262 const T uden = (usum < T(one - ftol)) ? usum : T(one - ftol);
263 for (std::size_t r = 0; r < K; ++r) QN(i, r) = T(UN(i, r) / T(one - uden));
268 if (!finiteCapUsed) {
269 for (std::size_t r = 0; r < K; ++r) {
270 UN(i, r) = T(TN(i, r) *
map_mean(ph.PH[i][r]));
271 if (std::isfinite(ns))
272 QN(i, r) = T(QN(i, r) + TN(i, r) *
276 RN(i, r) = T(QN(i, r) / TN(i, r));
282 for (std::size_t i = 0; i < M; ++i) {
284 if (L.
nodes[ind].nodetype != qn::NodeType::Queue || ARV[ind].order() == 0)
continue;
286 const bool fcfs = (sc == SchedStrategy::FCFS || sc == SchedStrategy::HOL ||
287 sc == SchedStrategy::FCFSPRPRIO);
288 if (!fcfs && sc != SchedStrategy::PS)
continue;
290 for (std::size_t r = 0; r < K; ++r) rho += UN(i, r);
291 for (std::size_t r = 0; r < K; ++r) {
293 const Map<T>& Srv = ph.PH[i][r];
296 if (etaqa_sz <= tcfg.
space_max && rho < T(one - ftol)) {
302 }
catch (
const Error&) {
309 if (lambda[r] > zero && V(i, r) > zero)
310 dep =
map_scale(dep, T(one / T(lambda[r] * V(i, r))));
315 std::vector<T> xnew(M * K, zero);
316 for (std::size_t i = 0; i < M; ++i)
317 for (std::size_t r = 0; r < K; ++r) xnew[i * K + r] = QN(i, r);
318 return std::make_pair(xnew, xref);
322 fo.
iter_max =
static_cast<std::size_t
>(
opt.iter_max);
334 out.
C.assign(K, zero);
335 out.
X.assign(K, zero);
Base error for the multiprecision C++ port.
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
std::vector< std::vector< bool > > disabled
std::vector< JobClass > classes
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< std::vector< std::size_t > > inchain
1-based class indices per chain
std::size_t node_of_station(std::size_t st) const
1-based node index of a station, and the reverse; 0 when absent.
std::vector< NodeDef > nodes
every node, in creation order
bool is_open_model() const
sn_is_open_model: EVERY class is open, which is not has_open_classes.
Damped fixed-point iteration, the shared driver of the decomposition algorithms.
The exception types the port throws.
The option and result types SolverMAM shares with its analyzers.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
Marked MAP (MMAP) algebra: per-class rates, class probabilities, superposition, normalization and sca...
The MMAP[K]/PH[K]/1 FCFS queue: per-class mean number in system and per-class queue-length distributi...
FpiResult< T > da_fpi(const std::function< std::pair< std::vector< T >, std::vector< T > >(const std::vector< T > &, std::size_t)> &iterfun, const std::vector< T > &x0, const FpiOptions &options=FpiOptions())
Damped fixed-point iteration, the shared driver of the decomposition algorithms.
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
const char * sched_to_text(SchedStrategy s)
std::vector< T > mmapph1fcfs_ncmean(const Mmap< T > &arrival, const std::vector< PhService< T > > &svc)
Per-class mean number of customers in the system, BUTools' 'ncMoms', 1.
MmckDetection< T > mam_detect_mmck(const qn::NetworkStruct< T > &L, std::size_t ist, const Mmap< T > &arv)
Port of mam_detect_mmck.m: is the exact M/M/c/K closed form legitimate at this station?
std::vector< std::vector< Map< T > > > DepTable
DEP{i,r}, the departure process of class r from i in (D0,D1) form.
TrafficConfig traffic_config(const MamOptions &opt)
The traffic step's view of SolverOptions('MAM').
std::vector< T > mmap_lambda(const Mmap< T > &m)
Alias kept for parity with the MATLAB name.
Mmap< T > mmap_hide_but(const Mmap< T > &in, std::size_t keep)
mmap_hide(m, setdiff(1:K, keep)): keep ONE mark, hide every other.
Map< T > qbd_depproc_etaqa(const Map< T > &arrival, const Map< T > &service, std::size_t n)
MAP descriptor of the departure process of a MAP/MAP/1-FCFS queue, ETAQA-truncated at level n (qbd_de...
T map_mean(const Map< T > &m)
Mean inter-arrival time, 1/lambda.
Map< T > qbd_depproc_etaqa_ps(const Map< T > &arrival, const Map< T > &service, std::size_t n)
MAP descriptor of the departure process of a MAP/MAP/1-PS queue, ETAQA-truncated at level n (qbd_depp...
Map< T > map_scale(const Map< T > &in, const T &new_mean)
Rescale time so that the mean inter-arrival time becomes new_mean.
mva::MvaSolution< T > solver_mam_decmmap(const qn::NetworkStruct< T > &L, const MamOptions &opt)
Port of solver_mam.m.
std::vector< Mmap< T > > solver_mam_traffic(const qn::NetworkStruct< T > &sn, const DepTable< T > &DEP, const TrafficConfig &config)
Port of solver_mam_traffic.m.
Map< T > map_normalize(const Map< T > &in)
Clamp negative off-diagonal entries of D0 and negative entries of D1 to zero, then rebuild the diagon...
MmckResult< T > qsys_mmck(const T &lambda, const T &mu, unsigned c, unsigned K)
Exact analysis of the M/M/c/K queue (truncated Erlang form).
A queueing network and its refreshed NetworkStruct.
Departure process of a MAP/MAP/1 queue: the ETAQA-truncated MAP descriptor under FCFS and under PS,...
Exact analysis of the M/M/c/K queue (truncated Erlang form).
Port of solver_mam_basic.m, the dec.source analyzer and the default algorithm of SolverMAM.
Port of solver_mam_basic_mmap.m, solver_mam_basic_mmap_inner.m and solver_mam_basic_mmap_closed....
The batch-arrival and batch-service queues of the MAM solver, and the two finite-capacity helpers sol...
Port of solver_mam_traffic.m and solver_mam_traffic_mmap.m: the traffic step of the dec....
Options mirroring the fields MATLAB reads off the options struct.
std::size_t miniter
iterations before the stopping test applies
bool relative_norm
config.da_norm, the increment norm.
The options SolverMAM reads.
A MAP as the pair of matrices (D0, D1).
The options.config fields the MMAP decomposition reads on top of MamOptions.
std::size_t etaqa_trunc
config.etaqa_trunc, the ETAQA level truncation of the departure process.
An MMAP: the underlying MAP plus the per-class arrival matrices.
std::size_t order() const
What mam_detect_mmck returns; muRate is meaningful only when isMmck.
The fields of options.config the traffic step reads.
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.
T meanQueueLength
L, mean number in system.