122 const std::vector<T>& c2a0,
const std::vector<T>& mu,
123 const std::vector<T>& cs2,
125 const std::size_t K = mu.size();
127 throw InputError(
"npfqn_traffic_idc: routing matrix and service rates disagree on K");
128 if (lambda0.size() != K || c2a0.size() != K || cs2.size() != K)
129 throw InputError(
"npfqn_traffic_idc: input vectors disagree on K");
145 for (std::size_t i = 0; i < K; ++i)
146 for (std::size_t j = 0; j < K; ++j) ImPt(i, j) = (i == j ? one : zero) - P(j, i);
147 ctx.
Xi = detail::matrix_inverse(ImPt);
149 ctx.
lambda.assign(K, zero);
150 for (std::size_t i = 0; i < K; ++i)
151 for (std::size_t j = 0; j < K; ++j) ctx.
lambda[i] += ctx.
Xi(i, j) * lambda0[j];
153 ctx.
rho.assign(K, zero);
154 for (std::size_t i = 0; i < K; ++i) ctx.
rho[i] = ctx.
lambda[i] / mu[i];
157 for (std::size_t j = 0; j < K; ++j)
158 for (std::size_t i = 0; i < K; ++i) ctx.
lam_ji(j, i) = ctx.
lambda[j] * P(j, i);
163 if (corrections.
alpha) {
164 for (std::size_t i = 0; i < K; ++i)
165 for (std::size_t j = 0; j < K; ++j)
166 ctx.
c2alpha(i, j) = two * ctx.
Xi(i, j) * P(i, j) * (one - P(i, j));
171 std::vector<Matrix<T>> Sigma(K,
Matrix<T>(K, K, zero));
172 for (std::size_t l = 0; l < K; ++l) {
174 for (std::size_t a = 0; a < K; ++a)
175 for (std::size_t b = 0; b < K; ++b) Sl(a, b) = -P(l, a) * P(l, b) * ctx.
lambda[l];
176 for (std::size_t a = 0; a < K; ++a) Sl(a, a) = P(l, a) * (one - P(l, a)) * ctx.
lambda[l];
180 for (std::size_t i = 0; i < K; ++i) Amat(i, i) = c2a0[i] * lambda0[i];
181 for (std::size_t l = 0; l < K; ++l)
182 for (std::size_t a = 0; a < K; ++a)
183 for (std::size_t b = 0; b < K; ++b) Amat(a, b) += Sigma[l](a, b);
186 std::vector<T> c2beta(K, zero);
187 for (std::size_t i = 0; i < K; ++i) {
190 for (std::size_t l = 0; l < K; ++l)
191 for (std::size_t b = 0; b < K; ++b) nu(l, b) = P(l, i) * ctx.
Xi(l, b);
194 for (std::size_t a = 0; a < K; ++a)
195 for (std::size_t b = 0; b < K; ++b) {
197 for (std::size_t c = 0; c < K; ++c) s += nu(a, c) * Amat(c, b);
201 for (std::size_t a = 0; a < K; ++a)
202 for (std::size_t b = 0; b < K; ++b) {
204 for (std::size_t c = 0; c < K; ++c) s += nuA(a, c) * nu(b, c);
208 for (std::size_t j = 0; j < K; ++j)
209 for (std::size_t k = 0; k < K; ++k) {
211 for (std::size_t c = 0; c < K; ++c)
212 s += nu(k, c) * Sigma[j](c, i) + nu(j, c) * Sigma[k](c, i);
217 for (std::size_t j = 0; j < K; ++j)
218 for (std::size_t k = j + 1; k < K; ++k) s += Z(j, k);
219 if (ctx.
lambda[i] > zero) c2beta[i] = (two / ctx.
lambda[i]) * s;
221 if (!corrections.
beta) {
222 c2beta.assign(K, zero);
228 const std::size_t Na = K, Naij = K * K, N = Na + Naij + Na;
230 std::vector<T> binf(N, zero);
231 for (std::size_t i = 0; i < N; ++i) E(i, i) = one;
232 for (std::size_t i = 0; i < K; ++i) {
233 if (ctx.
lambda[i] > zero) {
234 for (std::size_t j = 0; j < K; ++j)
235 E(i, Na + j * K + i) -= ctx.
lam_ji(j, i) / ctx.
lambda[i];
236 binf[i] = (lambda0[i] / ctx.
lambda[i]) * c2a0[i] + c2beta[i];
238 for (std::size_t j = 0; j < K; ++j) {
239 E(Na + i * K + j, Na + Naij + i) -= P(i, j);
240 binf[Na + i * K + j] = (one - P(i, j)) + ctx.
c2alpha(i, j);
242 E(Na + Naij + i, i) -= one;
244 const std::vector<T> csol =
solve(E, binf);
246 ctx.
c2a.assign(csol.begin(), csol.begin() +
static_cast<long>(K));
248 for (std::size_t i = 0; i < K; ++i)
249 for (std::size_t j = 0; j < K; ++j) ctx.
c2aij(i, j) = csol[Na + i * K + j];
250 ctx.
c2d.assign(csol.begin() +
static_cast<long>(Na + Naij), csol.end());
251 ctx.
c2x.assign(K, zero);
252 for (std::size_t i = 0; i < K; ++i) ctx.
c2x[i] = ctx.
c2a[i] + cs2[i];
276 const std::function<std::vector<T>(
const T&)>& a0IdcFun,
277 const std::function<std::vector<T>(
const std::vector<T>&)>& sIdcFun) {
279 "npfqn_traffic_idc_at requires transcendental arithmetic");
280 const std::size_t K = ctx.
K;
285 std::vector<T> h(K, zero);
286 for (std::size_t i = 0; i < K; ++i) h[i] = ctx.
rho[i] * ctx.
rho[i];
289 std::vector<T> w(K, one);
290 for (std::size_t i = 0; i < K; ++i) {
291 if (h[i] > zero && ctx.
c2x[i] > zero) {
292 const T num = (one - ctx.
rho[i]) * (one - ctx.
rho[i]) * ctx.
lambda[i] * t;
297 const std::vector<T> Ia0 = a0IdcFun(t);
298 std::vector<T> rhot(K, zero);
299 for (std::size_t i = 0; i < K; ++i) rhot[i] = ctx.
rho[i] * t;
300 const std::vector<T> Is = sIdcFun(rhot);
301 if (Ia0.size() != K || Is.size() != K)
302 throw InputError(
"npfqn_traffic_idc_at: an IDC handle returned the wrong length");
306 for (std::size_t i = 0; i < K; ++i)
307 for (std::size_t j = 0; j < K; ++j) alpha_t(i, j) = ctx.
c2alpha(i, j) * w[i];
310 std::vector<T> beta_t(K, zero);
311 for (std::size_t i = 0; i < K; ++i) {
313 std::vector<T> wj(K, zero);
314 for (std::size_t j = 0; j < K; ++j) {
315 if (h[j] > zero && ctx.
c2x[j] > zero && ctx.
P(j, i) > zero) {
316 const T aj = (one - ctx.
rho[j]) * (one - ctx.
rho[j]) * ctx.
P(j, i) * ctx.
lambda[j] * t;
321 for (std::size_t j = 0; j < K; ++j)
322 for (std::size_t k = 0; k < K; ++k)
323 if (j != k) s += Z(j, k) * wj[j];
324 if (ctx.
lambda[i] > zero) beta_t[i] = s / ctx.
lambda[i];
328 const std::size_t Na = K, Naij = K * K, N = Na + Naij + Na;
330 std::vector<T> b(N, zero);
331 for (std::size_t i = 0; i < N; ++i) E(i, i) = one;
332 for (std::size_t i = 0; i < K; ++i) {
333 if (ctx.
lambda[i] > zero) {
334 for (std::size_t j = 0; j < K; ++j)
335 E(i, Na + j * K + i) -= ctx.
lam_ji(j, i) / ctx.
lambda[i];
336 b[i] = (ctx.
lambda0[i] / ctx.
lambda[i]) * Ia0[i] + beta_t[i];
338 for (std::size_t j = 0; j < K; ++j) {
339 E(Na + i * K + j, Na + Naij + i) -= ctx.
P(i, j);
340 b[Na + i * K + j] = (one - ctx.
P(i, j)) + alpha_t(i, j);
342 E(Na + Naij + i, i) -= w[i];
343 b[Na + Naij + i] = (one - w[i]) * Is[i];
345 const std::vector<T> sol =
solve(E, b);
346 return std::vector<T>(sol.begin(), sol.begin() +
static_cast<long>(K));
Context returned by npfqn_traffic_idc, mirroring the MATLAB ctx struct.
std::vector< T > c2a0
(K) external arrival asymptotic IDC
Matrix< T > c2aij
(K x K) flow (i,j) asymptotic IDC
std::vector< T > rho
(K) utilization lambda_i / mu_i
std::vector< T > lambda0
(K) external arrival rate at each queue
std::vector< T > c2a
(K) total arrival asymptotic IDC
Matrix< T > Xi
(K x K) fundamental matrix (I - P')^{-1}
Matrix< T > lam_ji
(K x K) lam_ji(j,i) = lambda_j p_{j,i}
std::vector< Matrix< T > > zetaAll
(K) each (K x K), zetaAll[i](j,k) = zeta_{j,i;k,i}
std::vector< T > lambda
(K) total arrival rate at each queue