-- | Perform K-means clustering
kmeans :: Int                -- ^ The number of clusters
       -> MU.Matrix Double   -- ^ Input data stored as rows in a matrix
       -> KMeansOpts
       -> KMeans (U.Vector Double)
kmeans k mat opts
    | containNaN = error "Input data contains NaN."
    | otherwise = KMeans member cs grps sse'
  where
    containNaN =  U.any isNaN $ MU.flatten mat
    (member, cs, sse') = kmeans' initial (kmeansMaxIter opts) dat fn
    grps = if kmeansClusters opts
        then Just $ decode member $ MU.toRows mat
        else Nothing
    dat = U.enumFromN 0 $ MU.rows mat
    fn = unsafeTakeRow mat
    initial = runST $ do
        gen <- initialize $ kmeansSeed opts
        case kmeansMethod opts of
            Forgy -> forgy gen k dat fn
            KMeansPP -> kmeansPP gen k dat fn
            Centers c -> return c

kmeans :: Int                -- ^ The number of clusters
       -> MU.Matrix Double   -- ^ Input data stored as rows in a matrix
       -> KMeansOpts
       -> KMeans (U.Vector Double)
kmeans k mat opts
    | containNaN = error "Input data contains NaN."
    | otherwise = KMeans member cs grps sse'
  where
    containNaN =  U.any isNaN $ MU.flatten mat
    (member, cs, sse') = kmeans' initial (kmeansMaxIter opts) dat fn
    grps = if kmeansClusters opts
        then Just $ decode member $ MU.toRows mat
        else Nothing
    dat = U.enumFromN 0 $ MU.rows mat
    fn = unsafeTakeRow mat
    initial = runST $ do
        gen <- initialize $ kmeansSeed opts
        case kmeansMethod opts of
            Forgy -> forgy gen k dat fn
            KMeansPP -> kmeansPP gen k dat fn
            Centers c -> return c

kmeans k mat opts
    | containNaN = error "Input data contains NaN."
    | otherwise = KMeans member cs grps sse'
  where
    containNaN =  U.any isNaN $ MU.flatten mat
    (member, cs, sse') = kmeans' initial (kmeansMaxIter opts) dat fn
    grps = if kmeansClusters opts
        then Just $ decode member $ MU.toRows mat
        else Nothing
    dat = U.enumFromN 0 $ MU.rows mat
    fn = unsafeTakeRow mat
    initial = runST $ do
        gen <- initialize $ kmeansSeed opts
        case kmeansMethod opts of
            Forgy -> forgy gen k dat fn
            KMeansPP -> kmeansPP gen k dat fn
            Centers c -> return c
