60inline QsysRes qsys_mg1kk(
double alpha,
unsigned K,
const std::function<
double(
double)>& lst,
double ES) {
62 if (!(alpha > 0.0))
throw Error(
"qsys_mg1kk: alpha must be a positive real scalar");
63 if (K < 1)
throw Error(
"qsys_mg1kk: K must be a positive integer");
64 if (!lst)
throw Error(
"qsys_mg1kk: svc must be a Distribution or an LST function handle");
65 if (!(ES > 0.0))
throw Error(
"qsys_mg1kk: with an LST handle the mean service time ES must be given");
67 std::vector<double> Bs(K + 1);
68 for (
unsigned k = 0; k <= K; ++k) Bs[k] = lst(k * alpha);
69 double Bn = 1.0, S = 1.0;
70 for (
unsigned nn = 1; nn + 1 <= K; ++nn) {
71 Bn = Bn * (1.0 - Bs[nn]) / Bs[nn];
72 S += nchoosek_r(K - 1.0, nn) * Bn;
74 const double P0 = 1.0 / (1.0 + K * alpha * ES * S);
75 const double X = (1.0 - P0) / ES;
76 const double ET = K / X - 1.0 / alpha;
77 const double EW = ET - ES;
80 for (
unsigned j = 0; j < K; ++j) {
81 const unsigned nop = j == 0 ? K - 1 : K - j;
82 const unsigned base = j == 0 ? 0 : j - 1;
83 for (
unsigned i = 0; i <= nop; ++i) {
85 for (
unsigned l = 0; l <= i; ++l)
86 acc += ((l % 2) ? -1.0 : 1.0) * nchoosek_r(i, l) * Bs[nop - i + l];
87 P(j, base + i) += nchoosek_r(nop, i) * acc;
90 for (
unsigned j = 0; j < K; ++j) {
92 for (
unsigned i = 0; i < K; ++i) {
93 P(j, i) = std::max(P(j, i), 0.0);
96 for (
unsigned i = 0; i < K; ++i) P(j, i) /= rs;
100 std::vector<double> b(K, 0.0);
101 for (
unsigned r = 0; r + 1 < K; ++r)
102 for (
unsigned cc = 0; cc < K; ++cc) A(r, cc) = P(cc, r) - (r == cc ? 1.0 : 0.0);
103 for (
unsigned cc = 0; cc < K; ++cc) A(K - 1, cc) = 1.0;
105 std::vector<double> Pi =
solve(A, b);
107 std::vector<double> pn(K + 1, 0.0);
109 for (
unsigned n = 0; n < K; ++n) {
110 pn[n] = X * Pi[n] / ((
static_cast<double>(K) - n) * alpha);
114 if (std::fabs(pn[0] - P0) > 1e-6 * std::max(P0, 1e-12) || pn[K] < -1e-9) {
116 std::snprintf(buf,
sizeof buf,
117 "qsys_mg1kk: the embedded-chain distribution disagrees with the Takacs P_0 (%g vs %g): "
118 "the alternating arrival sums lost accuracy at K=%u; queueLengthDist, arrivalDist "
119 "and varQueueLength are returned as NaN, the means are unaffected.",
124 std::cerr <<
"[LINE] Warning: " << buf << std::endl;
125 std::fill(pn.begin(), pn.end(), std::numeric_limits<double>::quiet_NaN());
126 std::fill(Pi.begin(), Pi.end(), std::numeric_limits<double>::quiet_NaN());
128 pn[K] = std::max(pn[K], 0.0);
130 double EN = 0.0, EN2 = 0.0;
131 for (
unsigned n = 0; n <= K; ++n) {
133 EN2 +=
static_cast<double>(n) * n * pn[n];
136 r.
set(
"meanQueueLength", X * ET);
137 r.
set(
"varQueueLength", EN2 - EN * EN);
138 r.
set(
"meanQueueLengthQ", X * EW);
139 r.
set(
"meanWaitingTime", EW);
140 r.
set(
"meanSojournTime", ET);
141 r.
set(
"throughput", X);
142 r.
set(
"utilization", 1.0 - P0);
143 r.
set(
"meanOperating", K - X * ET);
144 r.
set(
"queueLengthDist", pn);
145 r.
set(
"arrivalDist", Pi);
146 r.
analyzer =
"exact:M/G/1/" + std::to_string(K) +
"/" + std::to_string(K);
QsysRes qsys_mg1kk(double alpha, unsigned K, const std::function< double(double)> &lst, double ES)
Exact M/G/1/K/K finite-source queue, service given by its LST.
std::vector< T > solve(const Matrix< T > &A, const std::vector< T > &b)
Convenience: solve Ax = b, leaving A and b untouched.