181 const std::vector<bool>& isps,
const std::vector<int>& pool,
182 const std::vector<int>& Ncap,
bool waitq,
double tol,
int iter_max) {
183 const std::size_t M = A.
rows();
184 const std::size_t R = A.
cols();
185 const std::size_t G = Ncap.size();
186 for (std::size_t g = 0; g < G; ++g)
189 "pfqn_oqnrc: Every token pool needs a positive integer number of tokens.");
190 std::vector<double> lamg(G, 0.0);
191 for (std::size_t r = 0; r < R; ++r) lamg[static_cast<std::size_t>(pool[r])] += lam[r];
192 for (std::size_t g = 0; g < G; ++g)
194 throw InputError(
ErrorKind{
"Argument"},
"pfqn_oqnrc: Every token pool needs a positive arrival rate.");
195 std::vector<bool> isdelay(M,
false);
196 for (std::size_t m = 0; m < M; ++m) isdelay[m] = std::isinf(nservers[m]);
197 std::vector<std::vector<double>> D(M, std::vector<double>(G, 0.0)), V = D, ES = D, ESrem = D;
198 for (std::size_t g = 0; g < G; ++g)
199 for (std::size_t m = 0; m < M; ++m) {
200 double asum = 0, as = 0, as2 = 0;
201 for (std::size_t r = 0; r < R; ++r) {
202 if (
static_cast<std::size_t
>(pool[r]) != g)
continue;
203 const double a = A(m, r), s = S(m, r);
206 as2 += a * (1 + SCV(m, r)) * s * s;
208 if (asum <= 0)
continue;
209 V[m][g] = asum / lamg[g];
210 D[m][g] = as / lamg[g];
211 ES[m][g] = D[m][g] / V[m][g];
212 if (!isdelay[m] && ES[m][g] > 0) {
213 const double c = nservers[m];
214 const double ES2 = as2 / asum;
215 ESrem[m][g] = (c - 1) / (c + 1) * ES[m][g] / c + 2 / (c + 1) * (1 / c) * ES2 / (2 * ES[m][g]);
218 oqnrc_detail::Lattice cs{lamg, D, V, ES, ESrem, S, pool, nservers, isdelay, isps, {}, {}, {}};
220 std::vector<double> q(G, 1.0);
221 std::vector<std::vector<double>> THC(G);
224 for (it = 1; it <= iter_max; ++it) {
225 std::vector<double> qnew = q;
226 for (std::size_t g = 0; g < G; ++g) {
227 std::vector<bool> hasSync(G,
true);
229 cs.
run(Ncap, hasSync, q,
false);
230 std::size_t base = 0;
231 for (std::size_t h = 0; h < G; ++h)
232 if (h != g) base +=
static_cast<std::size_t
>(Ncap[h]) * cs.
stride[h];
233 THC[g].assign(
static_cast<std::size_t
>(Ncap[g]), 0.0);
234 for (
int k = 1; k <= Ncap[g]; ++k)
235 THC[g][
static_cast<std::size_t
>(k - 1)] = cs.
TH[base +
static_cast<std::size_t
>(k) * cs.
stride[g]][g];
236 const double thN = THC[g].back();
237 if (lamg[g] >= thN * (1 - 1e-12)) {
239 std::snprintf(buf,
sizeof(buf),
240 "pfqn_oqnrc: Token pool %zu is unstable: its arrival rate %g is not below the "
241 "throughput %g of the region holding N=%d tokens, so the queue of waiting "
242 "arrivals grows without bound.",
243 g + 1, lamg[g], thN, Ncap[g]);
246 qnew[g] = 1 - lamg[g] / thN;
249 for (std::size_t g = 0; g < G; ++g) delta = std::max(delta, std::fabs(qnew[g] - q[g]));
251 if (G == 1 || delta < tol)
break;
253 if (it > iter_max) it = iter_max;
255 cs.
run(Ncap, std::vector<bool>(G,
true), q,
true);
256 const std::vector<double> THN = cs.
TH.back();
258 std::vector<double> Xg(G, 0.0), Qg(G, 0.0), Pg(G, 0.0);
259 for (std::size_t g = 0; g < G; ++g) {
262 double pik = 1.0,
sum = 0.0;
263 for (
int k = 0; k < Ncap[g]; ++k) {
265 pik *= lamg[g] / THC[g][
static_cast<std::size_t
>(k)];
267 const double rho = lamg[g] / THC[g].back();
268 const double Z =
sum + pik / (1 - rho);
269 Qg[g] = pik * rho / ((1 - rho) * (1 - rho)) / Z;
272 Pg[g] = std::max(0.0, 1 - THN[g] / lamg[g]);
280 res.
X.assign(R, 0.0);
281 res.
Qext.assign(R, 0.0);
282 res.
Ploss.assign(R, 0.0);
283 for (std::size_t r = 0; r < R; ++r) {
284 const std::size_t g =
static_cast<std::size_t
>(pool[r]);
285 for (std::size_t m = 0; m < M; ++m) {
286 const double t = A(m, r) * Xg[g] / lamg[g];
287 const double qq = THN[g] * A(m, r) / lamg[g] * cs.
ETr[m][r];
290 res.
U(m, r) = t * S(m, r) / (isdelay[m] ? 1.0 : nservers[m]);
291 res.
R(m, r) = t > 0 ? qq / t : 0.0;
293 res.
X[r] = lam[r] * Xg[g] / lamg[g];
294 res.
Qext[r] = Qg[g] * lam[r] / lamg[g];
295 res.
Ploss[r] = Pg[g];
OqnrcResult pfqn_oqnrc(const std::vector< double > &lam, const Matrix< double > &A, const Matrix< double > &S, const Matrix< double > &SCV, const std::vector< double > &nservers, const std::vector< bool > &isps, const std::vector< int > &pool, const std::vector< int > &Ncap, bool waitq, double tol, int iter_max)
Runs OQNRC.