mcmc-0.8.0.0: src/Mcmc/Internal/Shuffle.hs
-- |
-- Module : Mcmc.Internal.Shuffle
-- Description : Shuffle a list
-- Copyright : 2021 Dominik Schrempf
-- License : GPL-3.0-or-later
--
-- Maintainer : dominik.schrempf@gmail.com
-- Stability : unstable
-- Portability : portable
--
-- Creation date: Wed May 20 14:37:09 2020.
--
-- From https://wiki.haskell.org/Random_shuffle.
module Mcmc.Internal.Shuffle
( shuffle,
)
where
import Control.Monad
import Control.Monad.ST
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as M
import System.Random.Stateful
-- TODO: Remove shuffle, use System.Random.MWC.Distributions.uniformShuffle and
-- vectors.
-- | Shuffle a vector.
shuffle :: StatefulGen g m => [a] -> g -> m [a]
shuffle xs = grabble xs (length xs)
-- @grabble xs m n@ is /O(m*n')/, where @n' = min n (length xs)@. Choose @n'@
-- elements from @xs@, without replacement, and that @m@ times.
grabble :: StatefulGen g m => [a] -> Int -> g -> m [a]
grabble xs m gen = do
swaps <- forM [0 .. min (l - 1) m] $ \i -> do
j <- uniformRM (i, l) gen
return (i, j)
return $ (V.toList . V.take m . swapElems (V.fromList xs)) swaps
where
l = length xs - 1
swapElems :: V.Vector a -> [(Int, Int)] -> V.Vector a
swapElems xs swaps = runST $ do
mxs <- V.unsafeThaw xs
mapM_ (uncurry $ M.unsafeSwap mxs) swaps
V.unsafeFreeze mxs