5#ifndef LINE_API_MAM_MFQ_PRIO_QUEUE_H
6#define LINE_API_MAM_MFQ_PRIO_QUEUE_H
109namespace prio_detail {
111using multiregime_detail::blk;
112using multiregime_detail::expm0;
113using multiregime_detail::sylvester;
119 for (std::size_t i = 0; i < negC.
rows(); ++i)
120 for (std::size_t j = 0; j < negC.
cols(); ++j) negC(i, j) = -negC(i, j);
121 return sylvester(A, B, negC);
127 for (std::size_t i = 0; i < v.size(); ++i) m(i, i) = v[i];
132inline Matrix<double> neg(
const Matrix<double>& A) {
133 Matrix<double> B = A;
134 for (std::size_t i = 0; i < B.rows(); ++i)
135 for (std::size_t j = 0; j < B.cols(); ++j) B(i, j) = -B(i, j);
140inline double nchoosek(std::size_t n, std::size_t k) {
142 for (std::size_t i = 0; i < k; ++i)
143 r = r *
static_cast<double>(n - i) /
static_cast<double>(i + 1);
144 return std::floor(r + 0.5);
153inline Matrix<double> dreward(
const Matrix<double>& Q,
const Matrix<double>& R, std::size_t n,
155 const std::size_t NQ = Q.rows();
156 std::vector<std::size_t> ixz, ixp;
157 for (std::size_t i = 0; i < NQ; ++i)
158 if (std::fabs(R(i, i)) <= prec) ixz.push_back(i);
161 for (std::size_t i = 0; i < NQ; ++i)
162 if (R(i, i) > prec) ixp.push_back(i);
163 for (std::size_t i = 0; i < NQ; ++i)
164 if (R(i, i) < -prec) ixp.push_back(i);
165 const std::size_t Nz = ixz.size(), Np = ixp.size();
167 const Matrix<double> Rp = multiregime_detail::pick(R, ixp, ixp);
168 const Matrix<double> Qpp = multiregime_detail::pick(Q, ixp, ixp);
169 const Matrix<double> Qpz = multiregime_detail::pick(Q, ixp, ixz);
170 const Matrix<double> Qzp = multiregime_detail::pick(Q, ixz, ixp);
171 const Matrix<double> Qzz = multiregime_detail::pick(Q, ixz, ixz);
172 const Matrix<double> iRp =
inverse(Rp);
173 Matrix<double> inner = neg(Qpp);
179 for (std::size_t i = 0; i <= n; ++i) pw =
matmul(pw, base);
181 for (std::size_t i = 2; i <= n; ++i) fact *= static_cast<double>(i);
182 const double sgn = (n % 2 == 0) ? 1.0 : -1.0;
183 Matrix<double> dXvn =
matmul(pw, iRp);
184 for (std::size_t i = 0; i < Np; ++i)
185 for (std::size_t j = 0; j < Np; ++j) dXvn(i, j) *= sgn * fact;
189 Matrix<double> out(NQ, NQ, 0.0);
191 const Matrix<double> Z =
inverse(neg(Qzz));
192 const Matrix<double> ZQzp =
matmul(Z, Qzp);
193 const Matrix<double> QpzZ =
matmul(Qpz, Z);
194 const Matrix<double> tl =
matmul(
matmul(ZQzp, dXvn), QpzZ);
195 const Matrix<double> tr =
matmul(ZQzp, dXvn);
196 const Matrix<double> bl =
matmul(dXvn, QpzZ);
197 for (std::size_t i = 0; i < Nz; ++i) {
198 for (std::size_t j = 0; j < Nz; ++j) out(ixz[i], ixz[j]) = tl(i, j);
199 for (std::size_t j = 0; j < Np; ++j) out(ixz[i], ixp[j]) = tr(i, j);
201 for (std::size_t i = 0; i < Np; ++i)
202 for (std::size_t j = 0; j < Nz; ++j) out(ixp[i], ixz[j]) = bl(i, j);
204 for (std::size_t i = 0; i < Np; ++i)
205 for (std::size_t j = 0; j < Np; ++j) out(ixp[i], ixp[j]) = dXvn(i, j);
211 std::vector<std::size_t> ixz, ixp, ixn;
214inline SignSplit sign_split(
const Matrix<double>& C,
double prec) {
216 for (std::size_t i = 0; i < C.rows(); ++i) {
217 if (std::fabs(C(i, i)) <= prec) s.ixz.push_back(i);
218 else if (C(i, i) > prec) s.ixp.push_back(i);
219 else s.ixn.push_back(i);
229inline Matrix<double> embed_pn(
const Matrix<double>& X,
const SignSplit& s, std::size_t NF) {
230 Matrix<double> out(NF, NF, 0.0);
231 for (std::size_t i = 0; i < s.ixp.size(); ++i)
232 for (std::size_t j = 0; j < s.ixn.size(); ++j) out(s.ixp[i], s.ixn[j]) = X(i, j);
240inline std::vector<Matrix<double>> busy_period_reward_moms(
const Matrix<double>& F,
241 const Matrix<double>& C,
242 const Matrix<double>& D,
243 std::size_t numOfMoms,
double prec) {
244 const std::size_t NF = F.rows();
245 const SignSplit s = sign_split(C, prec);
246 const std::size_t Nz = s.ixz.size(), Np = s.ixp.size(), Nn = s.ixn.size();
248 const Matrix<double> Fzz = multiregime_detail::pick(F, s.ixz, s.ixz);
249 const Matrix<double> Fpz = multiregime_detail::pick(F, s.ixp, s.ixz);
250 const Matrix<double> Fmz = multiregime_detail::pick(F, s.ixn, s.ixz);
251 const Matrix<double> Fzp = multiregime_detail::pick(F, s.ixz, s.ixp);
252 const Matrix<double> Fpp = multiregime_detail::pick(F, s.ixp, s.ixp);
253 const Matrix<double> Fmp = multiregime_detail::pick(F, s.ixn, s.ixp);
254 const Matrix<double> Fzm = multiregime_detail::pick(F, s.ixz, s.ixn);
255 const Matrix<double> Fpm = multiregime_detail::pick(F, s.ixp, s.ixn);
256 const Matrix<double> Fmm = multiregime_detail::pick(F, s.ixn, s.ixn);
257 const Matrix<double> Cm = multiregime_detail::pick(C, s.ixn, s.ixn);
258 const Matrix<double> Cp = multiregime_detail::pick(C, s.ixp, s.ixp);
259 const Matrix<double> Dm = multiregime_detail::pick(D, s.ixn, s.ixn);
260 const Matrix<double> Dp = multiregime_detail::pick(D, s.ixp, s.ixp);
261 const Matrix<double> Dz = multiregime_detail::pick(D, s.ixz, s.ixz);
262 const Matrix<double> iCp =
inverse(Cp);
263 const Matrix<double> iCm =
inverse(neg(Cm));
266 Matrix<double> Zf(Nz, Nz, 0.0);
267 if (Nz > 0) Zf =
inverse(neg(Fzz));
268 auto cens = [&](
const Matrix<double>& A,
const Matrix<double>& Az,
269 const Matrix<double>& Zb) -> Matrix<double> {
270 if (Nz == 0)
return A;
273 std::vector<Matrix<double>> Fppd(numOfMoms + 1), Fpmd(numOfMoms + 1), Fmpd(numOfMoms + 1),
275 Fppd[0] =
matmul(iCp, cens(Fpp, Fpz, Fzp));
276 Fpmd[0] =
matmul(iCp, cens(Fpm, Fpz, Fzm));
277 Fmpd[0] =
matmul(iCm, cens(Fmp, Fmz, Fzp));
278 Fmmd[0] =
matmul(iCm, cens(Fmm, Fmz, Fzm));
279 for (std::size_t i = 1; i <= numOfMoms; ++i) {
280 const Matrix<double> dr = (Nz > 0) ? dreward(Fzz, Dz, i, prec) : Matrix<double>(0, 0, 0.0);
286 Fppd[i] = mfq_detail::sub(Fppd[i],
matmul(iCp, Dp));
287 Fmmd[i] = mfq_detail::sub(Fmmd[i],
matmul(iCm, Dm));
291 const FluidFundamental<double> ff =
293 const Matrix<double>& Psi = ff.Psi;
295 std::vector<Matrix<double>> BPM(numOfMoms + 1);
297 for (std::size_t i = 1; i <= numOfMoms; ++i) {
298 Matrix<double> X = mfq_detail::add(neg(
matmul(
matmul(Psi, Fmpd[i]), Psi)), Fpmd[i]);
299 for (std::size_t m = 0; m + 1 <= i; ++m) {
300 const double c = nchoosek(i, m);
301 Matrix<double> t = mfq_detail::add(
302 matmul(mfq_detail::add(Fppd[i - m],
matmul(Psi, Fmpd[i - m])), BPM[m]),
303 matmul(BPM[m], mfq_detail::add(Fmmd[i - m],
matmul(Fmpd[i - m], Psi))));
304 X = mfq_detail::add(X, mfq_detail::scale(t, c));
306 for (std::size_t l = 1; l + 1 <= i; ++l)
307 for (std::size_t m = 1; m + l <= i; ++m) {
308 const double c = nchoosek(i, l) * nchoosek(i - l, m);
309 const Matrix<double> t =
matmul(
matmul(BPM[l], Fmpd[i - l - m]), BPM[m]);
310 X = mfq_detail::add(X, mfq_detail::scale(t, c));
312 BPM[i] = lyap(mfq_detail::add(Fppd[0],
matmul(Psi, Fmpd[0])),
313 mfq_detail::add(Fmmd[0],
matmul(Fmpd[0], Psi)), X);
315 for (std::size_t i = 0; i <= numOfMoms; ++i) BPM[i] = embed_pn(BPM[i], s, NF);
322struct BusyPeriodDistr {
324 std::vector<Matrix<double>> Pn;
334inline BusyPeriodDistr busy_period_reward_distr(
const Matrix<double>& F,
const Matrix<double>& C,
335 const Matrix<double>& D,
double t,
336 std::size_t L,
double prec) {
337 const std::size_t NF = F.rows();
338 const SignSplit s = sign_split(C, prec);
339 const std::size_t Nz = s.ixz.size();
341 const Matrix<double> Fzz = multiregime_detail::pick(F, s.ixz, s.ixz);
342 const Matrix<double> Fpz = multiregime_detail::pick(F, s.ixp, s.ixz);
343 const Matrix<double> Fmz = multiregime_detail::pick(F, s.ixn, s.ixz);
344 const Matrix<double> Fzp = multiregime_detail::pick(F, s.ixz, s.ixp);
345 const Matrix<double> Fpp = multiregime_detail::pick(F, s.ixp, s.ixp);
346 const Matrix<double> Fmp = multiregime_detail::pick(F, s.ixn, s.ixp);
347 const Matrix<double> Fzm = multiregime_detail::pick(F, s.ixz, s.ixn);
348 const Matrix<double> Fpm = multiregime_detail::pick(F, s.ixp, s.ixn);
349 const Matrix<double> Fmm = multiregime_detail::pick(F, s.ixn, s.ixn);
350 const Matrix<double> Cm = multiregime_detail::pick(C, s.ixn, s.ixn);
351 const Matrix<double> Cp = multiregime_detail::pick(C, s.ixp, s.ixp);
352 const Matrix<double> Dm = multiregime_detail::pick(D, s.ixn, s.ixn);
353 const Matrix<double> Dp = multiregime_detail::pick(D, s.ixp, s.ixp);
354 const Matrix<double> Dz = multiregime_detail::pick(D, s.ixz, s.ixz);
355 const Matrix<double> iCp =
inverse(Cp);
356 const Matrix<double> iCm =
inverse(neg(Cm));
358 const double nu =
static_cast<double>(L) / t;
359 Matrix<double> Z(Nz, Nz, 0.0);
360 if (Nz > 0) Z =
inverse(mfq_detail::sub(mfq_detail::scale(Dz, nu), Fzz));
361 auto zc = [&](
const Matrix<double>& A,
const Matrix<double>& Az,
362 const Matrix<double>& Zb) -> Matrix<double> {
363 if (Nz == 0)
return A;
366 const Matrix<double> Fpp_e =
367 matmul(iCp, zc(mfq_detail::sub(Fpp, mfq_detail::scale(Dp, nu)), Fpz, Fzp));
368 const Matrix<double> Fpm_e =
matmul(iCp, zc(Fpm, Fpz, Fzm));
369 const Matrix<double> Fmp_e =
matmul(iCm, zc(Fmp, Fmz, Fzp));
370 const Matrix<double> Fmm_e =
371 matmul(iCm, zc(mfq_detail::sub(Fmm, mfq_detail::scale(Dm, nu)), Fmz, Fzm));
372 const Matrix<double> Psie =
375 std::vector<Matrix<double>> Pn;
377 Matrix<double> pr = Psie;
378 const Matrix<double> AM = mfq_detail::add(Fpp_e,
matmul(Psie, Fmp_e));
379 const Matrix<double> BM = mfq_detail::add(Fmm_e,
matmul(Fmp_e, Psie));
380 const Matrix<double> iCpDp = mfq_detail::scale(
matmul(iCp, Dp), nu);
381 const Matrix<double> iCmDm = mfq_detail::scale(
matmul(iCm, Dm), nu);
382 const Matrix<double> iCmFmp =
matmul(iCm, Fmp);
383 const Matrix<double> iCpFpz = (Nz > 0) ?
matmul(iCp, Fpz) : Matrix<double>(Fpp.rows(), 0, 0.0);
384 const Matrix<double> iCmFmz = (Nz > 0) ?
matmul(iCm, Fmz) : Matrix<double>(Fmm.rows(), 0, 0.0);
385 const Matrix<double> nuDzZ = (Nz > 0) ?
matmul(mfq_detail::scale(Dz, nu), Z)
386 : Matrix<double>(0, 0, 0.0);
388 for (std::size_t n = 1; n + 1 <= L; ++n) {
389 Matrix<double> CM = mfq_detail::add(
matmul(iCpDp, Pn[n - 1]),
matmul(Pn[n - 1], iCmDm));
390 for (std::size_t i = 1; i + 1 <= n; ++i)
391 CM = mfq_detail::add(CM,
matmul(
matmul(Pn[i], iCmFmp), Pn[n - i]));
394 Matrix<double> ZnuN = Z;
395 for (std::size_t i = 0; i < n; ++i) ZnuN =
matmul(ZnuN, nuDzZ);
396 CM = mfq_detail::add(CM,
matmul(
matmul(iCpFpz, ZnuN), Fzm));
397 CM = mfq_detail::sub(
399 for (std::size_t i = 0; i + 1 <= n; ++i) {
400 Matrix<double> Zk = Z;
401 for (std::size_t q = 0; q < n - i; ++q) Zk =
matmul(Zk, nuDzZ);
402 const Matrix<double> tail =
403 mfq_detail::add(Fzm,
matmul(Fzp, Psie));
405 CM = mfq_detail::add(
410 for (std::size_t i = 1; i + 1 <= n; ++i)
411 for (std::size_t j = 1; j + i <= n; ++j) {
412 Matrix<double> Zk = Z;
413 for (std::size_t q = 0; q < n - i - j; ++q) Zk =
matmul(Zk, nuDzZ);
414 CM = mfq_detail::add(
418 const Matrix<double> PM = lyap(AM, BM, CM);
420 pr = mfq_detail::add(pr, PM);
424 out.pr = embed_pn(pr, s, NF);
425 out.Pn.reserve(Pn.size());
426 for (
const Matrix<double>& P : Pn) out.Pn.push_back(embed_pn(P, s, NF));
442 using namespace prio_detail;
443 const std::size_t N = Q.
rows();
444 const std::size_t K = R.
rows();
445 if (Q.
cols() != N)
throw InputError(
"mfq_prio_queue: Q must be square");
447 throw InputError(
"mfq_prio_queue: R must have one column per background state");
448 if (K == 0)
throw InputError(
"mfq_prio_queue: at least one fluid class is required");
449 if (d <=
opt.prec)
throw InputError(
"mfq_prio_queue: the fluid service rate must be positive");
450 for (std::size_t k = 0; k < K; ++k)
451 for (std::size_t j = 0; j < N; ++j)
452 if (R(k, j) < -
opt.prec)
453 throw InputError(
"mfq_prio_queue: the fluid arrival rate cannot be negative");
454 if (
opt.erlMaxOrder < 2)
455 throw InputError(
"mfq_prio_queue: erlMaxOrder must be at least 2");
457 std::vector<std::size_t> classes =
opt.classes;
459 for (std::size_t k = 1; k <= K; ++k) classes.push_back(k);
460 for (std::size_t c : classes)
461 if (c < 1 || c > K)
throw InputError(
"mfq_prio_queue: class index out of range");
464 std::vector<double> lambda(K, 0.0);
465 for (std::size_t k = 0; k < K; ++k)
466 for (std::size_t j = 0; j < N; ++j) lambda[k] += pi[j] * R(k, j);
470 for (std::size_t ci = 0; ci < classes.size(); ++ci) {
471 const std::size_t k = classes[ci] - 1;
472 if (lambda[k] <= 0.0)
473 throw InputError(
"mfq_prio_queue: a requested class has zero mean input rate");
477 std::vector<double> agg(N, 0.0);
478 for (std::size_t kk = k; kk < K; ++kk)
479 for (std::size_t j = 0; j < N; ++j) agg[j] += R(kk, j);
480 std::vector<double> drift(N, 0.0);
481 for (std::size_t j = 0; j < N; ++j) drift[j] = agg[j] / d - 1.0;
484 const std::size_t KN = gs.
K.rows();
489 for (std::size_t i = 0; i < KN; ++i)
490 for (std::size_t j = 0; j < N; ++j) clok(i, j) = gs.
clo(i, j) * R(k, j) / lambda[k];
491 std::vector<double> ini = gs.
ini;
495 std::vector<double> rowsum(KN, 0.0);
496 for (std::size_t i = 0; i < KN; ++i)
497 for (std::size_t j = 0; j < N; ++j) rowsum[i] += clok(i, j);
498 const std::vector<double> delta =
mulvec(iKm, rowsum);
499 for (std::size_t i = 0; i < KN; ++i)
502 "mfq_prio_queue: the canonical similarity is singular for this class");
504 for (std::size_t i = 0; i < KN; ++i)
505 for (std::size_t j = 0; j < KN; ++j) K0(i, j) = Km(i, j) * delta[j] / delta[i];
507 for (std::size_t i = 0; i < KN; ++i)
508 for (std::size_t j = 0; j < N; ++j) K1(i, j) = clok(i, j) / delta[i];
509 std::vector<double> kappa(KN, 0.0);
510 for (std::size_t i = 0; i < KN; ++i) kappa[i] = ini[i] * delta[i];
519 for (std::size_t j = 0; j < N; ++j) mass0R += gs.
mass0[j] * R(k, j) / lambda[k];
521 const bool highest = (k + 1 == K);
524 if (
opt.stMoms > 0) {
525 std::vector<double> m(
opt.stMoms, 0.0);
530 for (std::size_t i = 1; i <=
opt.stMoms; ++i) {
531 fact *=
static_cast<double>(i);
533 const std::vector<double> v =
vecmul(
vecmul(ini, pw), clok);
535 for (
double x : v)
sum += x;
536 m[i - 1] = fact *
sum;
541 if (!
opt.stDistr.empty()) {
542 std::vector<double> v(
opt.stDistr.size(), 0.0);
543 for (std::size_t x = 0; x <
opt.stDistr.size(); ++x) {
549 for (std::size_t i = 0; i < KN; ++i)
550 for (std::size_t j = 0; j < KN; ++j) ImE(i, j) -= E(i, j);
551 const std::vector<double> w =
553 for (
double y : w) acc += y;
559 if (
opt.flMoms > 0 || !
opt.flDistr.empty()) {
561 std::vector<double> dr(N, 0.0);
562 for (std::size_t j = 0; j < N; ++j) dr[j] = R(k, j) - d;
565 const std::size_t FN = fs.
K.rows();
566 if (
opt.flMoms > 0) {
567 std::vector<double> m(
opt.flMoms, 0.0);
572 for (std::size_t i = 1; i <=
opt.flMoms; ++i) {
573 fact *=
static_cast<double>(i);
577 for (
double x : v)
sum += x;
578 m[i - 1] = fact *
sum;
583 if (!
opt.flDistr.empty()) {
584 std::vector<double> v(
opt.flDistr.size(), 0.0);
586 for (
double x : fs.
mass0) m0 += x;
587 for (std::size_t x = 0; x <
opt.flDistr.size(); ++x) {
593 for (std::size_t i = 0; i < FN; ++i)
594 for (std::size_t j = 0; j < FN; ++j) ImE(i, j) -= E(i, j);
595 const std::vector<double> w =
597 for (
double y : w) acc += y;
608 std::vector<double> lower(N, 0.0);
609 for (std::size_t kk = k + 1; kk < K; ++kk)
610 for (std::size_t j = 0; j < N; ++j) lower[j] += R(kk, j);
611 const std::size_t NF = KN + N;
613 for (std::size_t i = 0; i < KN; ++i) {
614 for (std::size_t j = 0; j < KN; ++j) F(i, j) = Km(i, j);
615 for (std::size_t j = 0; j < N; ++j) F(i, KN + j) = clok(i, j);
618 for (std::size_t i = 0; i < N; ++i) {
619 for (std::size_t j = 0; j < N; ++j) F(KN + i, KN + j) = Q(i, j);
620 Cmat(KN + i, KN + i) = lower[i] / d - 1.0;
622 std::vector<double> inis(NF, 0.0);
623 for (std::size_t i = 0; i < KN; ++i) inis[i] = ini[i];
625 auto make_D = [&](
bool fluid) {
627 for (std::size_t i = 0; i < N; ++i)
628 D(KN + i, KN + i) =
fluid ? R(k, i) : 1.0;
632 if (
opt.stMoms > 0) {
633 const std::vector<Matrix<double>> Tmp =
634 busy_period_reward_moms(F, Cmat, make_D(
false),
opt.stMoms,
opt.prec);
635 std::vector<double> m(
opt.stMoms, 0.0);
636 for (std::size_t i = 1; i < Tmp.size(); ++i) {
637 const std::vector<double> v =
vecmul(inis, Tmp[i]);
639 for (
double x : v)
sum += x;
640 m[i - 1] = ((i % 2 == 0) ? 1.0 : -1.0) *
sum;
644 if (!
opt.stDistr.empty()) {
645 std::vector<double> v(
opt.stDistr.size(), 0.0);
646 for (std::size_t x = 0; x <
opt.stDistr.size(); ++x) {
647 const BusyPeriodDistr bp = busy_period_reward_distr(
648 F, Cmat, make_D(
false),
opt.stDistr[x],
opt.erlMaxOrder,
opt.prec);
649 const std::vector<double> w =
vecmul(inis, bp.pr);
651 for (
double y : w) acc += y;
656 if (
opt.flMoms > 0) {
657 const std::vector<Matrix<double>> Tmp =
658 busy_period_reward_moms(F, Cmat, make_D(
true),
opt.flMoms,
opt.prec);
661 std::vector<std::vector<double>> FLDPn(Tmp.size(), std::vector<double>(N, 0.0));
662 for (std::size_t i = 0; i < Tmp.size(); ++i) {
663 const std::vector<double> row =
vecmul(inis, Tmp[i]);
664 for (std::size_t j = 0; j < N; ++j) FLDPn[i][j] = row[KN + j];
666 for (std::size_t j = 0; j < N; ++j)
667 FLDPn[i][j] += gs.
mass0[j] * R(k, j) / lambda[k];
671 for (std::size_t i = 0; i < N; ++i)
672 for (std::size_t j = 0; j < N; ++j) T2(i, j) = pi[j] - Q(i, j);
674 std::vector<std::vector<double>> FLPn;
676 std::vector<double> m(
opt.flMoms, 0.0);
677 for (std::size_t n = 1; n <=
opt.flMoms; ++n) {
678 const double nd =
static_cast<double>(n);
679 std::vector<double> a(N, 0.0);
680 for (std::size_t j = 0; j < N; ++j)
681 a[j] = -FLDPn[n - 1][j] + FLPn[n - 1][j] * R(k, j) / lambda[k];
682 const std::vector<double> aT =
vecmul(a, iTerm);
684 for (std::size_t j = 0; j < N; ++j) sumP += FLDPn[n][j];
685 for (std::size_t j = 0; j < N; ++j) sumP += nd * aT[j] * R(k, j);
686 std::vector<double> b(N, 0.0);
687 for (std::size_t j = 0; j < N; ++j)
688 b[j] = -FLPn[n - 1][j] * R(k, j) + FLDPn[n - 1][j] * lambda[k];
689 const std::vector<double> bT =
vecmul(b, iTerm);
690 std::vector<double> P(N, 0.0);
691 for (std::size_t j = 0; j < N; ++j) P[j] = sumP * pi[j] + nd * bT[j];
694 for (
double x : P)
sum += x;
695 m[n - 1] = ((n % 2 == 0) ? 1.0 : -1.0) *
sum;
699 if (!
opt.flDistr.empty()) {
700 std::vector<double> v(
opt.flDistr.size(), 0.0);
701 for (std::size_t x = 0; x <
opt.flDistr.size(); ++x) {
702 const double nu =
static_cast<double>(
opt.erlMaxOrder) /
opt.flDistr[x];
703 const BusyPeriodDistr bp = busy_period_reward_distr(
704 F, Cmat, make_D(
true),
opt.flDistr[x],
opt.erlMaxOrder,
opt.prec);
706 for (std::size_t i = 0; i < N; ++i)
707 for (std::size_t j = 0; j < N; ++j)
708 Wm(i, j) = (i == j ? nu * R(k, i) : 0.0) - Q(i, j);
710 std::vector<double> Psiy(N, 0.0);
712 const std::vector<double> row =
vecmul(inis, bp.Pn[0]);
713 std::vector<double> a(N, 0.0);
714 for (std::size_t j = 0; j < N; ++j)
715 a[j] = gs.
mass0[j] * R(k, j) / lambda[k] + row[KN + j];
716 const std::vector<double> t =
vecmul(a, iW);
717 for (std::size_t j = 0; j < N; ++j) Psiy[j] = lambda[k] * nu * t[j];
719 for (std::size_t i = 1; i < bp.Pn.size(); ++i) {
720 const std::vector<double> row =
vecmul(inis, bp.Pn[i]);
721 std::vector<double> a(N, 0.0);
722 for (std::size_t j = 0; j < N; ++j)
723 a[j] = lambda[k] * row[KN + j] + Psiy[j] * R(k, j);
724 const std::vector<double> t =
vecmul(a, iW);
725 for (std::size_t j = 0; j < N; ++j) Psiy[j] = nu * t[j];
728 for (
double y : Psiy) acc += y;
NumericError(const std::string &what)
Steady-state distribution of a continuous-time Markov chain.
The exception types the port throws.
Matrix exponential by scaling and squaring with a diagonal Pade approximant.
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
LU factorization with partial pivoting, templated on the number type.
Dense matrix and non-owning view.
Multi-regime FEEDBACK Markovian fluid queue: density, density derivative and distribution of the flui...
Core of the Markovian fluid queue: the fundamental matrices Psi, K, U and the matrix-exponential stat...
FluidFundamental< T > mfq_fundamental(const Matrix< T > &Fpp, const Matrix< T > &Fpm, const Matrix< T > &Fmp, const Matrix< T > &Fmm, const T &precision, unsigned maxNumIt, RiccatiMethod method)
Psi, K and U of a fluid queue whose drifts have been normalized to +-1.
FluidPrioResult mfq_prio_queue(const Matrix< double > &Q, const Matrix< double > &R, double d, const FluidPrioOptions &opt)
Fluid priority queue.
GeneralFluidSolution< T > mfq_general_solve(const Matrix< T > &Q, const Matrix< T > &R, const Matrix< T > &Q0, const T &prec)
Stationary law of a general Markovian fluid model, pi(x) = ini exp(K x) clo above level zero plus the...
std::vector< T > ctmc_solve(const Matrix< T > &Qin)
Steady-state distribution of a continuous-time Markov chain.
std::vector< T > vecmul(const std::vector< T > &v, const Matrix< T > &A)
Row vector times matrix, v A.
Matrix< T > inverse(const Matrix< T > &A)
Inverse by LU with one factorization and n back substitutions.
Matrix< T > matmul(const Matrix< T > &A, const Matrix< T > &B)
Matrix product A B.
std::vector< T > mulvec(const Matrix< T > &A, const std::vector< T > &v)
Matrix times column vector, A v.
Matrix< T > eye(std::size_t n)
Identity of order n.
Number-type abstraction for the templated API port.
Which measures to compute, and the numerical options.
std::size_t flMoms
number of fluid level moments, 0 = not wanted
std::size_t stMoms
number of sojourn time moments
std::vector< double > flDistr
levels at which the fluid CDF is wanted
std::size_t erlMaxOrder
Erlang order of the erlangization.
double prec
Riccati and matrix-quadratic tolerance.
std::vector< double > stDistr
times at which the sojourn CDF is wanted
std::vector< std::size_t > classes
1-based classes to analyze, empty = all
One entry per analyzed class, in the order given by FluidPrioOptions::classes.
std::vector< std::size_t > classes
the classes analyzed, 1-based
std::vector< std::vector< double > > stDistr
sojourn time CDF per class
std::vector< std::vector< double > > flDistr
fluid level CDF per class
std::vector< std::vector< double > > flMoms
fluid level moments per class
std::vector< std::vector< double > > stMoms
sojourn time moments per class
Stationary matrix-exponential solution of a general Markovian fluid model.
Matrix< T > K
matrix exponent of the density, Np x Np
std::vector< T > mass0
P(level 0, state j), length N.
std::vector< T > ini
initial vector of the density, length Np
Matrix< T > clo
closing matrix of the density, Np x N