LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
me_mqn.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_API_ME_ME_MQN_H
6#define LINE_API_ME_ME_MQN_H
7
8/**
9 * @file
10 * @ingroup api_me
11 * Maximum-entropy algorithm for mixed open/closed multiclass networks.
12 *
13 * Templated port of matlab/src/api/me/me_mqn.m, cross-checked against
14 * jar/src/main/java/jline/api/nc/Me_mqn.java. Kouvatsos (1994) notes that the
15 * closed two-stage treatment carries over to mixed networks (Section 2.3) but
16 * gives no algorithm; both LINE implementations compose the open (3.2) and
17 * closed (3.3) algorithms by product-form-style conditioning:
18 *
19 * 1. the open classes are solved by the open GE-type fixed point on the
20 * station set, ignoring the closed classes;
21 * 2. the closed classes are solved on servers whose capacity is reduced by
22 * the open-class utilization, mu_c(i,r) = mu(i,r) (1 - rho_o(i));
23 * 3. the open mean queue lengths are inflated by the closed occupancy,
24 * L_o(i,r) <- L_o(i,r) (1 + Lc(i)), at single-server stations.
25 *
26 * Steps 2-3 are exact in the BCMP product-form limit, where they reduce to
27 * the classical mixed MVA treatment, and are GE-type approximations
28 * otherwise. Only single-server and infinite-server stations are supported.
29 *
30 * ARITHMETIC: composes two tolerance-stopped fixed points.
31 * static_assert(num_traits<T>::has_transcendental)
32 */
33
34#include <cstddef>
35#include <vector>
36
37#include "line/api/me/me_cqn.h"
38#include "line/api/me/me_oqn.h"
40#include "line/num/number.h"
41#include "line/util/error.h"
42#include "line/util/matrix.h"
43
44namespace line {
45namespace me {
46
47namespace detail {
48
49/** Selects the given columns of an (M x R) matrix. */
50template <class T>
51Matrix<T> select_cols(const Matrix<T>& A, const std::vector<std::size_t>& cols) {
52 Matrix<T> B(A.rows(), cols.size(), num_traits<T>::from_int(0));
53 for (std::size_t i = 0; i < A.rows(); ++i)
54 for (std::size_t k = 0; k < cols.size(); ++k) B(i, k) = A(i, cols[k]);
55 return B;
56}
57
58} // namespace detail
59
60/**
61 * @brief Maximum-entropy algorithm for mixed open/closed multiclass networks.
62 *
63 * @param M number of stations
64 * @param R number of classes
65 * @param open_classes per-class flag, nonzero for an open class
66 * @param lambda0 external arrival rates (M x R), zero for closed classes
67 * @param Ca0 external arrival scvs (M x R)
68 * @param N populations (R); the entries of open classes are unused
69 * @param mu service rates (M x R)
70 * @param Cs service scvs (M x R)
71 * @param P routing, R matrices (M x M)
72 * @param c servers per station, 0 for an infinite-server station
73 * @param refstat reference station per class, -1 for the default
74 * @param insens insensitive discipline flags per station
75 * @param opt tolerance and iteration budget
76 */
77template <class T>
78MeResult<T> me_mqn(std::size_t M, std::size_t R, const std::vector<char>& open_classes,
79 const Matrix<T>& lambda0, const Matrix<T>& Ca0, const std::vector<long>& N,
80 const Matrix<T>& mu, const Matrix<T>& Cs, const std::vector<Matrix<T>>& P,
81 const std::vector<long>& c, const std::vector<long>& refstat,
82 const std::vector<char>& insens, const MeOptions& opt = MeOptions()) {
83 static_assert(num_traits<T>::has_transcendental, "me_mqn requires transcendental arithmetic");
84 detail::check_dims(M, R, mu, Cs, P, c, insens, "me_mqn");
85 if (open_classes.size() != R) throw InputError("me_mqn: one open flag per class");
86 if (N.size() != R) throw InputError("me_mqn: one population per class");
87 if (refstat.size() != R) throw InputError("me_mqn: one reference station per class");
88
89 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
90 std::vector<std::size_t> oc, cc;
91 for (std::size_t r = 0; r < R; ++r) (open_classes[r] ? oc : cc).push_back(r);
92
93 MeResult<T> out;
94 out.L = Matrix<T>(M, R, zero);
95 out.W = Matrix<T>(M, R, zero);
96 out.Ca = Matrix<T>(M, R, one);
97 out.Cd = Matrix<T>(M, R, one);
98 out.lambda = Matrix<T>(M, R, zero);
99 out.rho = Matrix<T>(M, R, zero);
100 out.X.assign(R, zero);
101 out.converged = true;
102
103 // Step 1: open classes
104 std::vector<T> rho_o(M, zero);
105 if (!oc.empty()) {
106 std::vector<Matrix<T>> Po;
107 for (std::size_t k = 0; k < oc.size(); ++k) Po.push_back(P[oc[k]]);
108 const MeResult<T> ro =
109 me_oqn(M, oc.size(), detail::select_cols(lambda0, oc), detail::select_cols(Ca0, oc),
110 detail::select_cols(mu, oc), detail::select_cols(Cs, oc), Po, c, insens, opt);
111 out.iter += ro.iter;
112 out.converged = out.converged && ro.converged;
113 for (std::size_t i = 0; i < M; ++i)
114 for (std::size_t k = 0; k < oc.size(); ++k) {
115 out.L(i, oc[k]) = ro.L(i, k);
116 out.Ca(i, oc[k]) = ro.Ca(i, k);
117 out.Cd(i, oc[k]) = ro.Cd(i, k);
118 out.lambda(i, oc[k]) = ro.lambda(i, k);
119 out.rho(i, oc[k]) = ro.rho(i, k);
120 }
121 for (std::size_t i = 0; i < M; ++i) {
122 if (detail::is_is(c, i)) continue;
123 for (std::size_t k = 0; k < oc.size(); ++k) rho_o[i] += ro.rho(i, k);
124 }
125 for (std::size_t k = 0; k < oc.size(); ++k) out.X[oc[k]] = ro.X[k];
126 }
127
128 // Step 2: closed classes on servers with reduced capacity
129 if (!cc.empty()) {
130 Matrix<T> mu_c = detail::select_cols(mu, cc);
131 for (std::size_t i = 0; i < M; ++i) {
132 if (detail::is_is(c, i)) continue;
133 T fac = one - rho_o[i];
134 if (fac < zero) fac = zero;
135 for (std::size_t k = 0; k < cc.size(); ++k) mu_c(i, k) *= fac;
136 }
137 std::vector<Matrix<T>> Pc;
138 std::vector<long> Nc, refc;
139 for (std::size_t k = 0; k < cc.size(); ++k) {
140 Pc.push_back(P[cc[k]]);
141 Nc.push_back(N[cc[k]]);
142 refc.push_back(refstat[cc[k]]);
143 }
144 const MeResult<T> rc = me_cqn(M, cc.size(), Nc, mu_c, detail::select_cols(Cs, cc), Pc, c,
145 refc, insens, opt);
146 out.iter += rc.iter;
147 out.converged = out.converged && rc.converged;
148 for (std::size_t i = 0; i < M; ++i)
149 for (std::size_t k = 0; k < cc.size(); ++k) {
150 out.L(i, cc[k]) = rc.L(i, k);
151 out.W(i, cc[k]) = rc.W(i, k);
152 out.Ca(i, cc[k]) = rc.Ca(i, k);
153 out.Cd(i, cc[k]) = rc.Cd(i, k);
154 out.lambda(i, cc[k]) = rc.lambda(i, k);
155 if (detail::is_is(c, i)) {
156 out.rho(i, cc[k]) = rc.rho(i, k);
157 } else {
158 T fac = one - rho_o[i];
159 if (fac < zero) fac = zero;
160 out.rho(i, cc[k]) = rc.rho(i, k) * fac;
161 }
162 }
163 for (std::size_t k = 0; k < cc.size(); ++k) out.X[cc[k]] = rc.X[k];
164 }
165
166 // Step 3: inflate the open queue lengths by the closed occupancy
167 if (!oc.empty() && !cc.empty()) {
168 for (std::size_t i = 0; i < M; ++i) {
169 if (detail::is_is(c, i)) continue;
170 T Lc_i = zero;
171 for (std::size_t k = 0; k < cc.size(); ++k) Lc_i += out.L(i, cc[k]);
172 for (std::size_t k = 0; k < oc.size(); ++k) out.L(i, oc[k]) *= (one + Lc_i);
173 }
174 }
175 for (std::size_t i = 0; i < M; ++i)
176 for (std::size_t k = 0; k < oc.size(); ++k)
177 if (out.lambda(i, oc[k]) > zero)
178 out.W(i, oc[k]) = out.L(i, oc[k]) / out.lambda(i, oc[k]);
179 return out;
180}
181
182} // namespace me
183} // namespace line
184
185#endif // LINE_API_ME_ME_MQN_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Dense matrix and non-owning view.
Maximum-entropy algorithm for closed multiclass queueing networks.
Maximum-entropy algorithm for open multiclass queueing networks.
Shared declarations for the maximum-entropy (Kouvatsos) queueing network algorithms.
MeResult< T > me_mqn(std::size_t M, std::size_t R, const std::vector< char > &open_classes, const Matrix< T > &lambda0, const Matrix< T > &Ca0, const std::vector< long > &N, const Matrix< T > &mu, const Matrix< T > &Cs, const std::vector< Matrix< T > > &P, const std::vector< long > &c, const std::vector< long > &refstat, const std::vector< char > &insens, const MeOptions &opt=MeOptions())
Maximum-entropy algorithm for mixed open/closed multiclass networks.
Definition me_mqn.h:78
MeResult< T > me_cqn(std::size_t M, std::size_t R, const std::vector< long > &N, const Matrix< T > &mu, const Matrix< T > &Cs, const std::vector< Matrix< T > > &P, const std::vector< long > &c, const std::vector< long > &refstat_in, const std::vector< char > &insens, const MeOptions &opt=MeOptions())
Maximum-entropy algorithm for closed multiclass queueing networks.
Definition me_cqn.h:463
MeResult< T > me_oqn(std::size_t M, std::size_t R, const Matrix< T > &lambda0, const Matrix< T > &Ca0, const Matrix< T > &mu, const Matrix< T > &Cs, const std::vector< Matrix< T > > &P, const std::vector< long > &c, const std::vector< char > &insens, const MeOptions &opt=MeOptions())
Maximum-entropy algorithm for open multiclass queueing networks.
Definition me_oqn.h:121
Number-type abstraction for the templated API port.
Iteration control, mirroring the MATLAB options struct.
Definition me_types.h:58
Mean-value results shared by the open, closed and mixed algorithms.
Definition me_types.h:157
Matrix< T > rho
utilizations (M x R)
Definition me_types.h:163
Matrix< T > L
mean queue lengths (M x R)
Definition me_types.h:158
Matrix< T > W
mean response times (M x R)
Definition me_types.h:159
Matrix< T > Ca
arrival scvs (M x R)
Definition me_types.h:160
Matrix< T > Cd
departure scvs (M x R)
Definition me_types.h:161
std::vector< T > X
class throughputs (R)
Definition me_types.h:164
long iter
fixed-point iterations performed
Definition me_types.h:165
Matrix< T > lambda
per-station throughputs (M x R)
Definition me_types.h:162