///|
/// Finite capacity includes customers in service. Exponential abandonment
/// acts only on waiting customers, not on those already in service.
pub(all) struct FiniteQueue {
  arrival : Double
  service : Double
  servers : Int
  capacity : Int
  abandonment : Double
} derive(Debug, ToJson)

///|
pub(all) struct FiniteMetrics {
  states : Array[Double]
  mean_system : Double
  mean_queue : Double
  mean_busy : Double
  blocked_fraction : Double
  admitted_rate : Double
  service_rate : Double
  abandon_rate : Double
  mean_residence : Double
} derive(Debug, ToJson)

///|
pub fn FiniteQueue::analyze(
  self : FiniteQueue,
) -> FiniteMetrics raise QueueError {
  rate(self.arrival, "arrival")
  rate(self.service, "service")
  positive(self.service, "service")
  rate(self.abandonment, "abandonment")
  servers(self.servers)
  if self.capacity < self.servers || self.capacity > 10000 {
    raise Limit("finite capacity must be between server count and 10000")
  }
  let birth = Array::make(self.capacity, self.arrival)
  let death = Array::makei(self.capacity, i => {
    let n = i + 1
    n.min(self.servers).to_double() * self.service +
    (n - self.servers).max(0).to_double() * self.abandonment
  })
  // Per-state total rates are sums of individually valid input rates;
  // stationary_birth_death applies its public rate bound as well.
  let states = stationary_birth_death(birth, death)
  let mut mean_system = 0.0
  let mut mean_queue = 0.0
  let mut mean_busy = 0.0
  for n in 0..