sampling

Basic sampling functionality for Haskell.
git clone git://git.jtobin.io/sampling.git
Log | Files | Refs | README | LICENSE

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