///|
pub struct Clusters {
  features : Array[String]
  basis : Basis
  centers : Array[Array[Double]]
  assignments : Array[Int]
  counts : Array[Int]
  inertia : Double
  iterations : Int
  converged : Bool
}

///|
fn squared_euclidean(a : Array[Double], b : Array[Double]) -> Double {
  let mut total = 0.0
  for j in 0.. (Int, Double) {
  let mut best = 0
  let mut value = squared_euclidean(row, centers[0])
  for j in 1.. Clusters raise CodaError {
  let n = data.row_count()
  let p = data.part_count() - 1
  if count < 1 || count > n || count > 64 {
    raise Invalid("cluster count must be 1..min(N,64)")
  }
  if max_iterations < 1 || max_iterations > 500 {
    raise Budget("iterations must be 1..500")
  }
  if n.to_double() *
    p.to_double() *
    count.to_double() *
    max_iterations.to_double() >
    2.0e7 {
    raise Budget("k-means exceeds 20 million coordinate comparisons")
  }
  let b = helmert_basis(data.part_count())
  let rows = data.ilr_rows(b)
  let centers = [rows[0].copy()]
  while centers.length() < count {
    let mut farthest = 0
    let mut separation = -1.0
    for i, row in rows {
      let (_, value) = closest_center(row, centers)
      if value > separation {
        separation = value
        farthest = i
      }
    }
    centers.push(rows[farthest].copy())
  }
  let assignments = Array::make(n, -1)
  let mut converged = false
  let mut iterations = 0
  for iteration in 0.. 0 {
        for j in 0..

Array[Int] { self.assignments.copy() } ///| pub fn Clusters::counts(self : Clusters) -> Array[Int] { self.counts.copy() } ///| pub fn Clusters::inertia(self : Clusters) -> Double { self.inertia } ///| pub fn Clusters::iterations(self : Clusters) -> Int { self.iterations } ///| pub fn Clusters::converged(self : Clusters) -> Bool { self.converged } ///| pub fn Clusters::centers( self : Clusters, ) -> Array[Array[Double]] raise CodaError { self.centers.map(c => ilr_inverse(c, self.basis)) } ///| pub fn Clusters::predict( self : Clusters, data : Dataset, ) -> Array[Int] raise CodaError { matching_features(data.features, self.features) data .ilr_rows(self.basis) .map(row => { let (k, _) = closest_center(row, self.centers) k }) }