///|
/// Exact FCFS response tail for M/M/c: an exponential service time plus
/// a mixture of zero wait and exponential delayed wait. Not GI/G/c.
pub fn Mmc::response_survival(
self : Mmc,
time : Double,
) -> Double raise QueueError {
nonnegative(time, "response threshold")
let metrics = self.analyze()
let spare = self.service * self.servers.to_double() - self.arrival
let a = spare.min(self.service)
let d = (spare - self.service).abs()
let at = a * time
if at > 750.0 {
return 0.0
}
let x = d * time
let extra = if x < 0.0001 {
at * (1.0 - x / 2.0 + x * x / 6.0 - x * x * x / 24.0)
} else {
a / d * (1.0 - @math.exp(-x))
}
let conditional = @math.exp(-at) * (1.0 + extra)
let result = (1.0 - metrics.delay_probability) *
@math.exp(-self.service * time) +
metrics.delay_probability * conditional
finite(result, "response survival")
result.max(0.0).min(1.0)
}
///|
/// Response quantile from the exact continuous tail. The unit quantile is
/// infinite even with zero load because exponential service is unbounded.
pub fn Mmc::response_quantile(
self : Mmc,
p : Double,
) -> Double raise QueueError {
probability(p, "response quantile")
let metrics = self.analyze()
if p == 1.0 {
raise Invalid("unit response quantile is infinite")
}
if p == 0.0 {
return 0.0
}
let target = 1.0 - p
let mut hi = metrics.mean_response
for _ in 0..<1024 {
if self.response_survival(hi) <= target {
break
}
hi *= 2.0
finite(hi, "response quantile bracket")
}
if self.response_survival(hi) > target {
raise Numerical("response quantile could not be bracketed")
}
let mut lo = 0.0
for _ in 0..<100 {
let mid = lo + (hi - lo) * 0.5
if self.response_survival(mid) > target {
lo = mid
} else {
hi = mid
}
}
hi
}