86 unsigned c,
const std::vector<T>& alpha,
88 const std::vector<T>& p = std::vector<T>(),
89 const std::vector<T>& q = std::vector<T>(),
90 const std::vector<T>& gamma = std::vector<T>(),
91 double maxOrbit = -1.0) {
93 "qsys_retrial_isstable reports an infinite margin, which needs a type holding Inf");
98 const std::size_t K = lambda.size();
99 if (K == 0)
throw InputError(
"qsys_retrial_isstable: lambda must have at least one entry.");
100 const std::vector<T> muv = expand(mu, K,
"mu", one);
101 const std::vector<T> pv = expand(p, K,
"p", one);
102 const std::vector<T> qv = expand(q, K,
"q", one);
103 const std::vector<T> gv = expand(gamma, K,
"gamma", zero);
104 const std::vector<T> av = expand(alpha, K,
"alpha", zero);
106 for (std::size_t k = 0; k < K; ++k)
107 bad = bad || lambda[k] < zero || !(muv[k] > zero) || pv[k] < zero || pv[k] > one ||
108 qv[k] < zero || qv[k] > one || gv[k] < zero;
110 throw InputError(
"qsys_retrial_isstable: Invalid input: rates must be positive, c >= 1, and p, q in [0, 1].");
113 if (std::isfinite(maxOrbit) && maxOrbit >= 0) {
116 out.
reason =
"finite orbit: the chain is finite";
119 std::vector<bool> selfLimiting(K);
120 bool all =
true, anyLim =
false;
121 for (std::size_t k = 0; k < K; ++k) {
123 pv[k] == zero || lambda[k] == zero;
124 all = all && selfLimiting[k];
125 anyLim = anyLim || selfLimiting[k];
130 out.
reason =
"every orbit loses customers at a rate growing with its size";
136 "qsys_retrial_isstable: No known stability condition for a multiclass retrial queue "
137 "that mixes persistent classes with self-limiting ones (q < 1 or orbit impatience).");
138 for (std::size_t k = 0; k < K; ++k)
139 if (!(av[k] > zero)) {
141 out.
margin = T(zero - inf);
142 out.
reason =
"LINEAR retrial with zero retrial rate: the orbit never empties";
146 for (std::size_t k = 0; k < K; ++k) load = T(load + lambda[k] * pv[k] / muv[k]);
149 out.
reason =
"LINEAR retrial, persistent orbit: sum(lambda.*p./mu) < c";
155 "qsys_retrial_isstable: No known necessary-and-sufficient stability condition for a "
156 "multiclass retrial queue under the CONSTANT policy.");
157 if (!(av[0] > zero)) {
159 out.
margin = T(zero - inf);
160 out.
reason =
"CONSTANT retrial with zero retrial rate: the orbit never empties";
164 out.
margin = T(av[0] * (one - x) + av[0] * (one - qv[0]) * x - lambda[0] * pv[0] * x);
166 out.
reason =
"CONSTANT retrial: lambda*p*x < alpha*(1-x) + alpha*(1-q)*x, x = ErlangB((lambda+alpha)/mu, c)";
std::vector< T > expand(const std::vector< T > &v, std::size_t K, const char *name, const T &def)
A scalar broadcast to K entries, or a K-vector left as it is.
RetrialStabilityResult< T > qsys_retrial_isstable(const std::vector< T > &lambda, const std::vector< T > &mu, unsigned c, const std::vector< T > &alpha, RetrialPolicy policy=RetrialPolicy::LINEAR, const std::vector< T > &p=std::vector< T >(), const std::vector< T > &q=std::vector< T >(), const std::vector< T > &gamma=std::vector< T >(), double maxOrbit=-1.0)