///|
pub struct SampleStatistics {
  count : Int
  mean : Double
  variance : Double
  standard_deviation : Double
  minimum : Double
  maximum : Double
} derive(Debug, Eq)

///|
pub fn summarize_samples(values : Array[Double]) -> SampleStatistics {
  if values.length() == 0 {
    abort("cannot summarize an empty sample set")
  }
  let mut count = 0
  let mut mean = 0.0
  let mut second_moment = 0.0
  let mut minimum = 1.0e308
  let mut maximum = -1.0e308
  for value in values {
    count += 1
    let delta = value - mean
    mean += delta / count.to_double()
    let corrected_delta = value - mean
    second_moment += delta * corrected_delta
    if value < minimum {
      minimum = value
    }
    if value > maximum {
      maximum = value
    }
  }
  let variance = if count == 0 {
    0.0
  } else {
    second_moment / count.to_double()
  }
  {
    count,
    mean,
    variance,
    standard_deviation: variance.sqrt(),
    minimum,
    maximum,
  }
}

///|
pub fn quantile(values : Array[Double], probability : Double) -> Double {
  if values.length() == 0 {
    abort("cannot calculate a quantile from an empty sample set")
  }
  if probability < 0.0 || probability > 1.0 {
    abort("quantile probability must be between zero and one")
  }
  let sorted = values.copy()
  sorted.sort()
  let position = probability * (sorted.length() - 1).to_double()
  let lower_index = position.floor().to_int()
  let upper_index = if lower_index + 1 >= sorted.length() {
    lower_index
  } else {
    lower_index + 1
  }
  let fraction = position - lower_index.to_double()
  sorted[lower_index] + (sorted[upper_index] - sorted[lower_index]) * fraction
}