Internal.hs (3568B)
1 {-# LANGUAGE FlexibleContexts #-} 2 3 -- Much of the code in this module is a modification of that found in the 4 -- 'foldl' library by Gabriel Gonzalez. Its license is reproduced below. 5 6 -- Copyright (c) 2013 Gabriel Gonzalez 7 -- All rights reserved. 8 -- 9 -- Redistribution and use in source and binary forms, with or without modification, 10 -- are permitted provided that the following conditions are met: 11 -- * Redistributions of source code must retain the above copyright notice, 12 -- this list of conditions and the following disclaimer. 13 -- * Redistributions in binary form must reproduce the above copyright notice, 14 -- this list of conditions and the following disclaimer in the documentation 15 -- and/or other materials provided with the distribution. 16 -- * Neither the name of Gabriel Gonzalez nor the names of other contributors 17 -- may be used to endorse or promote products derived from this software 18 -- without specific prior written permission. 19 -- 20 -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 -- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 -- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 24 -- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 -- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 -- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 -- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 -- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 -- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 module Numeric.Sampling.Internal ( 32 randomN 33 ) where 34 35 import Control.Foldl (FoldM (..)) 36 import Control.Monad (when) 37 import Control.Monad.Primitive 38 import Data.Vector.Generic (Mutable, Vector) 39 import qualified Data.Vector.Generic as V 40 import Data.Vector.Generic.Mutable (MVector) 41 import qualified Data.Vector.Generic.Mutable as M 42 import System.Random.MWC 43 44 data VectorState = Incomplete {-# UNPACK #-} !Int | Complete 45 46 data RandomNState m v a = RandomNState 47 { _size :: !VectorState 48 , _reservoir :: !(Mutable v (PrimState m) a) 49 , _position :: {-# UNPACK #-} !Int 50 , _gen :: !(Gen (PrimState m)) 51 } 52 53 randomN 54 :: (PrimMonad m, Vector v a) 55 => Int -> Gen (PrimState m) -> FoldM m a (Maybe (v a)) 56 randomN n gen = FoldM step begin done where 57 step 58 :: (PrimMonad m, MVector (Mutable v) a) 59 => RandomNState m v a -> a -> m (RandomNState m v a) 60 step (RandomNState (Incomplete m) mv i g) a = do 61 M.write mv m a 62 let m' = m + 1 63 let s = if n <= m' then Complete else Incomplete m' 64 return $! RandomNState s mv (i + 1) g 65 66 step (RandomNState Complete mv i g) a = do 67 r <- uniformR (0, i - 1) g 68 when (r < n) (M.unsafeWrite mv r a) 69 return (RandomNState Complete mv (i + 1) g) 70 71 begin = do 72 mv <- M.new n 73 let s = if n <= 0 then Complete else Incomplete 0 74 return (RandomNState s mv 1 gen) 75 76 done :: (PrimMonad m, Vector v a) => RandomNState m v a -> m (Maybe (v a)) 77 done (RandomNState (Incomplete _) _ _ _) = return Nothing 78 done (RandomNState Complete mv _ _) = do 79 v <- V.freeze mv 80 return (Just v) 81 {-# INLINABLE randomN #-} 82