110 const std::vector<double>& cs) {
112 const std::size_t K = lambda.size();
113 if (mu.size() != K || cs.size() != K)
114 throw InputError(
ErrorKind(
"Argument"),
"qsys_mg1_sjf: lambda, mu and cs must have the same length");
115 for (std::size_t r = 0; r < K; ++r)
116 if (!(lambda[r] > 0.0) || !(mu[r] > 0.0) || !(cs[r] >= 0.0))
117 throw InputError(
ErrorKind(
"Argument"),
"qsys_mg1_sjf: lambda and mu must be positive, cs non-negative");
118 double lambda_total = 0.0, rho_util = 0.0, lES2 = 0.0;
119 for (std::size_t r = 0; r < K; ++r) {
120 lambda_total += lambda[r];
121 rho_util += lambda[r] / mu[r];
122 lES2 += lambda[r] * (1.0 + cs[r] * cs[r]) / (mu[r] * mu[r]);
125 std::vector<SjfFit> fits(K);
126 double rate_min = std::numeric_limits<double>::infinity(), rate_max = 0.0;
127 for (std::size_t r = 0; r < K; ++r) {
128 fits[r] = sjf_fit(mu[r], cs[r]);
129 rate_min = std::min(rate_min, fits[r].rate_min);
130 rate_max = std::max(rate_max, fits[r].rate_max);
132 const double xmax = 40.0 / rate_min;
133 const long N = std::min(2000000L, std::max(20000L,
static_cast<long>(std::ceil(200.0 * rate_max / rate_min))));
134 const std::size_t np =
static_cast<std::size_t
>(N) + 1;
135 std::vector<double> x(np), fmix(np, 0.0);
137 for (std::size_t i = 0; i < np; ++i) x[i] = xmax * static_cast<double>(i) /
static_cast<double>(N);
139 std::vector<std::vector<double>> pdf(K, std::vector<double>(np));
140 for (std::size_t r = 0; r < K; ++r) {
141 const double p = lambda[r] / lambda_total;
142 for (std::size_t i = 0; i < np; ++i) {
143 pdf[r][i] = sjf_pdf(fits[r], x[i]);
144 fmix[i] += p * pdf[r][i];
148 std::vector<double> Wx(np);
150 for (std::size_t i = 0; i < np; ++i) {
151 if (i > 0) cum += 0.5 * (x[i] - x[i - 1]) * (x[i] * fmix[i] + x[i - 1] * fmix[i - 1]);
152 const double denom = std::max(1.0 - lambda_total * cum, 1e-12);
153 Wx[i] = (lES2 / 2.0) / (denom * denom);
155 auto trapz = [&](
const std::vector<double>& y) {
157 for (std::size_t i = 1; i < np; ++i) s += 0.5 * (x[i] - x[i - 1]) * (y[i] + y[i - 1]);
161 std::vector<double> Wq(K), Qi(K), y(np);
162 out.
W.assign(K, 0.0);
164 for (std::size_t r = 0; r < K; ++r) {
165 for (std::size_t i = 0; i < np; ++i) y[i] = Wx[i] * pdf[r][i];
167 out.
W[r] = Wq[r] + 1.0 / mu[r];
168 Qi[r] = lambda[r] * out.
W[r];
171 out.
rhohat = Q / (1.0 + Q);
172 for (std::size_t i = 0; i < np; ++i) y[i] = x[i] * fmix[i] * Wx[i];
173 out.
res.
set(
"meanSojournTime", out.
W);
174 out.
res.
set(
"meanWaitingTime", Wq);
175 out.
res.
set(
"meanQueueLength", Qi);
176 out.
res.
set(
"utilization", rho_util);
177 out.
res.
set(
"conservationResidual", lambda_total * trapz(y) - rho_util * lES2 / (2.0 * (1.0 - rho_util)));