5#ifndef LINE_API_QSYS_QSYS_MM1_DPS_H
6#define LINE_API_QSYS_QSYS_MM1_DPS_H
66inline void dps_states_rec(std::size_t K,
unsigned rem, std::vector<unsigned>& cur,
67 std::vector<std::vector<unsigned>>& out) {
68 if (cur.size() == K) {
72 for (
unsigned v = 0; v <= rem; ++v) {
74 dps_states_rec(K, rem - v, cur, out);
80inline std::vector<std::vector<unsigned>> dps_states(std::size_t K,
unsigned Ncut) {
81 std::vector<std::vector<unsigned>> out;
82 std::vector<unsigned> cur;
84 dps_states_rec(K, Ncut, cur, out);
90std::vector<T> dps_solve_trunc(
const std::vector<T>& lambda,
const std::vector<T>& mu,
91 const std::vector<T>& w,
unsigned Ncut) {
92 const std::size_t K = lambda.size();
93 const std::vector<std::vector<unsigned>> S = dps_states(K, Ncut);
94 const std::size_t n = S.size();
95 std::vector<std::size_t> stride(K, 1);
96 for (std::size_t k = 1; k < K; ++k) stride[k] = stride[k - 1] * (Ncut + 1);
97 std::vector<std::size_t> index(stride[K - 1] * (Ncut + 1), n);
98 for (std::size_t i = 0; i < n; ++i) {
100 for (std::size_t k = 0; k < K; ++k) key += S[i][k] * stride[k];
104 const T zero = num_traits<T>::from_int(0);
105 Matrix<T> Q(n, n, zero);
106 for (std::size_t i = 0; i < n; ++i) {
108 for (std::size_t k = 0; k < K; ++k) tot += S[i][k];
110 for (std::size_t k = 0; k < K; ++k)
111 den += num_traits<T>::from_int(
static_cast<long>(S[i][k])) * w[k];
113 for (std::size_t k = 0; k < K; ++k) key += S[i][k] * stride[k];
114 for (std::size_t k = 0; k < K; ++k) {
115 if (tot < Ncut) Q(i, index[key + stride[k]]) += lambda[k];
117 Q(i, index[key - stride[k]]) +=
118 mu[k] * num_traits<T>::from_int(
static_cast<long>(S[i][k])) * w[k] / den;
121 for (std::size_t i = 0; i < n; ++i) {
123 for (std::size_t j = 0; j < n; ++j)
124 if (j != i) s += Q(i, j);
128 std::vector<T> EN(K, zero);
129 for (std::size_t i = 0; i < n; ++i)
130 for (std::size_t k = 0; k < K; ++k)
131 EN[k] += pi[i] * num_traits<T>::from_int(
static_cast<long>(S[i][k]));
149 const std::vector<T>& w,
const T& tol,
unsigned maxCutoff) {
151 "qsys_mm1_dps requires transcendental arithmetic");
152 const std::size_t K = lambda.size();
153 if (mu.size() != K || w.size() != K)
154 throw InputError(
"qsys_mm1_dps: lambda, mu and w must have the same length");
155 if (K == 0)
throw InputError(
"qsys_mm1_dps: at least one class is required");
157 for (std::size_t k = 0; k < K; ++k)
158 if (lambda[k] <= zero || mu[k] <= zero || w[k] <= zero)
159 throw InputError(
"qsys_mm1_dps: lambda, mu and w must all be positive");
161 for (std::size_t k = 0; k < K; ++k) rho += lambda[k] / mu[k];
162 if (rho >= one)
throw InputError(
"qsys_mm1_dps: system is unstable, rho >= 1");
166 unsigned N =
static_cast<unsigned>(std::max(16.0, std::ceil(lt / lr)));
167 if (N > maxCutoff) N = maxCutoff;
169 std::vector<T> ENprev = detail::dps_solve_trunc(lambda, mu, w, N);
170 while (N < maxCutoff) {
171 const unsigned N2 = std::min(2u * N, maxCutoff);
172 const std::vector<T> EN = detail::dps_solve_trunc(lambda, mu, w, N2);
174 for (std::size_t k = 0; k < K; ++k) {
175 const T d =
num_abs(T(EN[k] - ENprev[k]));
176 if (d > gap) gap = d;
179 if (gap < tol)
break;
181 if (N2 == maxCutoff)
break;
187 for (std::size_t k = 0; k < K; ++k) r.
T_[k] = ENprev[k] / lambda[k];
194 const std::vector<T>& w) {
Steady-state distribution of a continuous-time Markov chain.
The exception types the port throws.
Dense matrix and non-owning view.
std::vector< T > ctmc_solve(const Matrix< T > &Qin)
Steady-state distribution of a continuous-time Markov chain.
Mm1DpsResult< T > qsys_mm1_dps(const std::vector< T > &lambda, const std::vector< T > &mu, const std::vector< T > &w, const T &tol, unsigned maxCutoff)
Multiclass M/M/1 under DPS (discriminatory processor sharing), solved numerically on the truncated po...
Number-type abstraction for the templated API port.
Shared return type and arithmetic helpers for the templated qsys port.
std::vector< T > T_
per-class mean response time
T rho
total utilization sum_k lambda_k/mu_k