5#ifndef LINE_API_QSYS_MMK_QED_H
6#define LINE_API_QSYS_MMK_QED_H
93 "qsys_mmk_qed_alpha needs erfc and exp");
96 if (beta <= zero)
return one;
102 const T Phi = erfc(T(-beta / sqrt(two))) / two;
103 return phi / (phi + beta * Phi);
117 const T a = lambda / mu;
119 for (
unsigned j = 1; j <= s; ++j)
122 return rho >= one ? one : T(b / (one - rho * (one - b)));
137 if (lambda <= zero)
throw InputError(
"qsys_mmk_qed: the arrival rate lambda must be positive");
138 if (mu <= zero)
throw InputError(
"qsys_mmk_qed: the service rate mu must be positive");
139 if (s < 1)
throw InputError(
"qsys_mmk_qed: the number of servers s must be at least 1");
147 if (r.
beta <= zero) {
165template <
class T,
class Fn>
173 throw InputError(
"qsys_mmk_qed_staffing: no server slack meets the target");
175 const T two = num_traits<T>::from_int(2);
176 for (
int i = 0; i < 200; ++i) {
177 const T mid = (lo + hi) / two;
178 if (f(mid) < num_traits<T>::from_int(0)) {
184 return (lo + hi) / two;
189bool qed_meets(
const T& lambda,
const T& mu,
unsigned s,
const T& target,
QedCriterion crit,
190 const T& deadline,
const T& level) {
191 const T sT = num_traits<T>::from_int(
static_cast<long>(s));
192 if (sT * mu <= lambda)
return false;
194 const T wq = c / (sT * mu - lambda);
200 return (num_traits<T>::from_int(1) - c * exp(-(sT * mu - lambda) * deadline)) >= level;
224 bool exact =
false) {
229 throw InputError(
"qsys_mmk_qed_staffing: the arrival rate lambda must be positive");
230 if (mu <= zero)
throw InputError(
"qsys_mmk_qed_staffing: the service rate mu must be positive");
235 const T a = lambda / mu;
239 if (!(target > zero && target < one))
241 "qsys_mmk_qed_staffing: for the delay criterion the target must be in (0,1)");
242 betaTarget = detail::qed_solve<T>([&](
const T& b) {
return target -
qsys_mmk_qed_alpha(b); });
245 if (!(target > zero))
247 "qsys_mmk_qed_staffing: for the meanwait criterion the target must be positive");
249 betaTarget = detail::qed_solve<T>(
253 if (!(level > zero && level < one) || !(deadline > zero))
254 throw InputError(
"qsys_mmk_qed_staffing: the service level must be in (0,1) and "
255 "the deadline positive");
256 betaTarget = detail::qed_solve<T>([&](
const T& b) {
257 const T sApprox = a + b * sqrt(a);
258 return (one -
qsys_mmk_qed_alpha(b) * exp(-mu * b * sqrt(sApprox) * deadline)) - level;
265 unsigned s =
static_cast<unsigned>(sl);
269 while (!detail::qed_meets(lambda, mu, s, target, crit, deadline, level)) {
272 throw InputError(
"qsys_mmk_qed_staffing: the exact refinement passed 10^7 servers "
273 "without meeting the target");
275 while (s > 1 && detail::qed_meets(lambda, mu, s - 1, target, crit, deadline, level)) --s;
Delay(model, name): the infinite-server station.
The exception types the port throws.
QsysQedResult< T > qsys_mmk_qed(const T &lambda, const T &mu, unsigned s)
Halfin-Whitt QED approximation for the M/M/s queue, and the square-root staffing rule that inverts it...
T qsys_mmk_qed_erlangc(unsigned s, const T &lambda, const T &mu)
Erlang C by the Erlang B recursion B_j = a B_{j-1}/(j + a B_{j-1}), which never forms a^j/j!
QsysQedStaffingResult< T > qsys_mmk_qed_staffing(const T &lambda, const T &mu, const T &target, QedCriterion crit=QedCriterion::Delay, const T &deadline=num_traits< T >::from_int(0), const T &level=num_traits< T >::from_int(0), bool exact=false)
Square-root staffing of the M/M/s queue.
QedCriterion
Which target the staffing rule is asked to meet.
T qsys_mmk_qed_alpha(const T &beta)
The Halfin-Whitt delay-probability function alpha(beta); 1 at beta <= 0.
Number-type abstraction for the templated API port.
Shared return type and arithmetic helpers for the templated qsys port.
QED measures of the M/M/s queue.
T meanWaitDelayed
E[W | W > 0] = 1/(s mu - lambda), exact for M/M/s.
T meanQueueLength
E[Q] = lambda E[W].
T offeredLoad
a = lambda/mu, in erlangs
T beta
the QED server slack (s-a)/sqrt(s)
T meanWait
E[W] = alpha(beta)/(s mu - lambda).
T meanNumber
E[N] = a + E[Q].
T trafficIntensity
rho = a/s
Outcome of the square-root staffing rule.
T meanWait
the QED mean wait at the recommended s
T offeredLoad
a = lambda/mu
T betaTarget
the slack the target asks for, before rounding s up
T serviceLevel
P(W <= deadline), for the service-level criterion.
T probDelay
the QED delay probability at the recommended s
unsigned numServers
the recommended s
bool exactUsed
whether the exact Erlang C refinement was applied
T beta
the slack achieved, (s-a)/sqrt(s)