LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
solver_mapqn.h
Go to the documentation of this file.
1#pragma once
2/**
3 * @file solver_mapqn.h
4 * @ingroup line_solvers
5 * @brief SolverMVA method 'amva.mapqn': the horizontal-cut mean value analysis (mapqn_amva) of
6 * a closed multiclass model with one exponential delay station and one FCFS single-server
7 * queue whose class-r service is a MAP.
8 *
9 * `mva_mapqn_reason` is the one structural predicate behind the method: list_valid_methods
10 * drops the name when it is nonempty and `solver_mapqn` raises it, so the offered and run
11 * answers cannot drift apart. Port of matlab/src/solvers/MVA/mva_mapqn_reason.m and
12 * solver_mva_mapqn_analyzer.m.
13 */
14#include <cmath>
15#include <cstddef>
16#include <limits>
17#include <string>
18#include <vector>
19
25#include "line/util/error.h"
26
27namespace line {
28namespace mva {
29
30namespace mapqn_detail {
31template <class T>
32bool is_delay(const qn::Station<T>& st) {
33 return st.sched == lang::SchedStrategy::INF || std::isinf(st.nservers);
34}
35inline bool is_markovian(lang::ProcessType t) {
37 return t == ProcessType::EXP || t == ProcessType::ERLANG || t == ProcessType::HYPEREXP ||
38 t == ProcessType::PH || t == ProcessType::APH || t == ProcessType::COXIAN ||
39 t == ProcessType::COX2 || t == ProcessType::MAP || t == ProcessType::MMPP2;
40}
41} // namespace mapqn_detail
42
43/** The reason 'amva.mapqn' cannot solve L, or "" when it can (and "" for any other method). */
44template <class T>
45std::string mva_mapqn_reason(const qn::NetworkStruct<T>& L, const std::string& method) {
46 using mapqn_detail::is_delay;
47 using mapqn_detail::is_markovian;
48 if (qn::mva_base_method(method) != "mapqn") return "";
49 const std::size_t M = L.nstations, R = L.nclasses;
50 if (M != 2)
51 return "solver_mapqn: Method 'amva.mapqn' requires exactly two stations: one delay (infinite server) "
52 "and one FCFS queue";
53 std::size_t id = 0, ndelay = 0;
54 for (std::size_t i = 0; i < M; ++i)
55 if (is_delay(L.stations[i])) { id = i; ++ndelay; }
56 if (ndelay != 1)
57 return "solver_mapqn: Method 'amva.mapqn' requires exactly one delay (infinite-server) station and one queue";
58 const std::size_t iq = 1 - id;
59 if (L.stations[iq].sched != lang::SchedStrategy::FCFS)
60 return "solver_mapqn: Method 'amva.mapqn' requires FCFS scheduling at the queue; station " +
61 std::to_string(iq + 1) + " is not FCFS";
62 if (L.stations[iq].nservers != 1.0)
63 return "solver_mapqn: Method 'amva.mapqn' supports a single-server queue only";
64 const std::vector<double> njobs = L.njobs();
65 for (std::size_t r = 0; r < R; ++r)
66 if (std::isinf(njobs[r])) return "solver_mapqn: Method 'amva.mapqn' supports closed models only";
67 if (L.nclosedjobs() <= 0) return "solver_mapqn: Method 'amva.mapqn' supports closed models only";
68 const std::size_t nd = L.station_to_node[id], nq = L.station_to_node[iq];
69 const T one = num_traits<T>::from_int(1);
70 for (std::size_t r = 0; r < R; ++r) {
71 if (njobs[r] <= 0) continue;
72 if (L.procid(id + 1, r + 1) != lang::ProcessType::EXP)
73 return "solver_mapqn: Method 'amva.mapqn' requires exponential think times; class " +
74 std::to_string(r + 1) + " has a non-exponential think time";
75 if (!is_markovian(L.procid(iq + 1, r + 1)) || L.service[iq][r].disabled)
76 return "solver_mapqn: Method 'amva.mapqn' requires a Markovian (MAP-representable) service process "
77 "at the queue; class " + std::to_string(r + 1) + " is not";
78 if (std::fabs(num_traits<T>::to_double(L.route_eff(r + 1, r + 1, nd, nq) - one)) > 1e-12 ||
79 std::fabs(num_traits<T>::to_double(L.route_eff(r + 1, r + 1, nq, nd) - one)) > 1e-12)
80 return "solver_mapqn: Method 'amva.mapqn' requires every class to cycle delay -> queue -> delay "
81 "without class switching; class " + std::to_string(r + 1) + " does not";
82 }
83 return "";
84}
85
86template <class T>
88 using mapqn_detail::is_delay;
89 const std::string reason = mva_mapqn_reason(L, "mapqn");
90 if (!reason.empty()) throw UnsupportedError(reason);
91 (void)opt;
92 const std::size_t M = L.nstations, R = L.nclasses;
93 std::size_t id = 0;
94 for (std::size_t i = 0; i < M; ++i)
95 if (is_delay(L.stations[i])) id = i;
96 const std::size_t iq = 1 - id;
97 const std::vector<double> pop = L.njobs();
98 std::vector<int> N(R, 0);
99 std::vector<T> mu(R, num_traits<T>::from_int(1));
100 std::vector<Matrix<T>> D0s(R), D1s(R);
101 for (std::size_t r = 0; r < R; ++r) {
102 N[r] = static_cast<int>(std::lround(pop[r]));
103 if (N[r] > 0) {
104 mu[r] = L.rates(id, r);
105 const mam::Map<T> m = lang::dist_to_map(L.service[iq][r]);
106 D0s[r] = m.D0;
107 D1s[r] = m.D1;
108 } else {
109 D0s[r] = Matrix<T>(1, 1, num_traits<T>::from_int(-1)); // absent class: inert single phase
110 D1s[r] = Matrix<T>(1, 1, num_traits<T>::from_int(1));
111 }
112 }
113 const mapqn::MapqnAmvaResult<T> res = mapqn::mapqn_amva<T>(mu, D0s, D1s, N);
114 const T zero = num_traits<T>::from_int(0);
115 MvaSolution<T> sol;
116 sol.Q = Matrix<T>(M, R, zero);
117 sol.U = Matrix<T>(M, R, zero);
118 sol.R = Matrix<T>(M, R, zero);
119 sol.Tp = Matrix<T>(M, R, zero);
120 sol.C.assign(R, zero);
121 sol.X.assign(R, zero);
122 for (std::size_t r = 0; r < R; ++r) {
123 if (N[r] <= 0 || num_traits<T>::to_double(res.X[r]) <= 0.0) continue;
124 const T X = res.X[r];
125 sol.X[r] = X;
126 sol.Q(iq, r) = res.Qq[r];
127 sol.U(iq, r) = res.U[r];
128 sol.Tp(iq, r) = X;
129 sol.R(iq, r) = res.Qq[r] / X;
130 sol.Q(id, r) = X / mu[r];
131 sol.U(id, r) = X / mu[r];
132 sol.Tp(id, r) = X;
133 sol.R(id, r) = num_traits<T>::from_int(1) / mu[r];
134 sol.C[r] = num_traits<T>::from_int(N[r]) / X;
135 }
136 sol.method = "amva.mapqn";
137 int iter = 1;
138 for (std::size_t r = 0; r < R; ++r) iter *= (N[r] + 1);
139 sol.iter = iter;
140 sol.lG = std::numeric_limits<double>::quiet_NaN();
141 return sol;
142}
143
144} // namespace mva
145} // namespace line
UnsupportedError(const std::string &what)
Definition error.h:51
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.
ProcessType procid(std::size_t ist, std::size_t r) const
sn.procid(i,r): the process type of a (station, class) pair.
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 ...
T route_eff(std::size_t r, std::size_t s, std::size_t i, std::size_t j) const
The routing actually in force: the expansion when there is one, else P.
std::vector< double > njobs() const
sn.njobs: the population of each class, infinite for an open one.
double nclosedjobs() const
sn.nclosedjobs: the total population of the closed classes.
std::vector< std::size_t > station_to_node
(nstations) 1-based node index
What refreshProcessRepresentations and refreshLST compute FROM a distribution: the (D0,...
The exception types the port throws.
Horizontal-cut mean value analysis for a MAP server (SolverMVA method 'amva.mapqn').
The option and result types every MVA analyzer shares.
mam::Map< T > dist_to_map(const Distrib< T > &d)
ProcessType
Distribution kinds, with the values of MATLAB ProcessType.
Definition lang_types.h:483
MapqnAmvaResult< T > mapqn_amva(const std::vector< T > &mu_in, const std::vector< Matrix< T > > &D0s, const std::vector< Matrix< T > > &D1s, const std::vector< int > &N)
Definition mapqn_amva.h:108
std::string mva_mapqn_reason(const qn::NetworkStruct< T > &L, const std::string &method)
The reason 'amva.mapqn' cannot solve L, or "" when it can (and "" for any other method).
MvaSolution< T > solver_mapqn(const qn::NetworkStruct< T > &L, const MvaOptions &opt)
std::string mva_base_method(const std::string &method)
SolverMVA.getFeatureSet, plus getMethodFeatureSet's per-method deltas.
A queueing network and its refreshed NetworkStruct.
The DECLARED side of the gate: one feature set per solver.
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53
Matrix< T > D1
Definition map_moment.h:55
Matrix< T > D0
Definition map_moment.h:54
X: class throughputs; Qq: mean queue lengths at the MAP station (job in service included); U: busy pr...
Definition mapqn_amva.h:45
The options SolverMVA reads.
Definition mva_types.h:31
Class-level results, the [Q,U,R,T,C,X] of the MATLAB analyzers.
Definition mva_types.h:96
std::vector< T > X
Definition mva_types.h:98
double lG
log of the normalizing constant, the reference's lG.
Definition mva_types.h:118
std::vector< T > C
Definition mva_types.h:98