packages feed

mwc-random 0.4.1.1 → 0.5.0.0

raw patch · 2 files changed

+87/−77 lines, 2 filesdep +primitivedep +vectordep −uvectordep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: primitive, vector

Dependencies removed: uvector

Dependency ranges changed: base

API changes (from Hackage documentation)

- System.Random.MWC: instance Read Seed
- System.Random.MWC: instance Variate Integer
- System.Random.MWC: uniformArray :: (UA a, Variate a) => Gen s -> Int -> ST s (UArr a)
+ System.Random.MWC: uniformVector :: (PrimMonad m, Variate a) => Gen (PrimState m) -> Int -> m (Vector a)
- System.Random.MWC: class Variate a
+ System.Random.MWC: class (Unbox a) => Variate a
- System.Random.MWC: create :: ST s (Gen s)
+ System.Random.MWC: create :: (PrimMonad m) => m (Gen (PrimState m))
- System.Random.MWC: initialize :: UArr Word32 -> ST s (Gen s)
+ System.Random.MWC: initialize :: (PrimMonad m) => Vector Word32 -> m (Gen (PrimState m))
- System.Random.MWC: normal :: Gen s -> ST s Double
+ System.Random.MWC: normal :: (PrimMonad m) => Gen (PrimState m) -> m Double
- System.Random.MWC: restore :: Seed -> ST s (Gen s)
+ System.Random.MWC: restore :: (PrimMonad m) => Seed -> m (Gen (PrimState m))
- System.Random.MWC: save :: Gen s -> ST s Seed
+ System.Random.MWC: save :: (PrimMonad m) => Gen (PrimState m) -> m Seed
- System.Random.MWC: uniform :: (Variate a) => Gen s -> ST s a
+ System.Random.MWC: uniform :: (Variate a, PrimMonad m) => Gen (PrimState m) -> m a
- System.Random.MWC: withSystemRandom :: (forall s. Gen s -> ST s a) -> IO a
+ System.Random.MWC: withSystemRandom :: (PrimMonad m) => (Gen (PrimState m) -> m a) -> IO a

Files

System/Random/MWC.hs view
@@ -2,7 +2,7 @@     ScopedTypeVariables #-} -- | -- Module    : System.Random.MWC--- Copyright : (c) 2009 Bryan O'Sullivan+-- Copyright : (c) 2009, 2010 Bryan O'Sullivan -- License   : BSD3 -- -- Maintainer  : bos@serpentine.com@@ -33,7 +33,7 @@     , save     , restore     -- * Helper functions-    , uniformArray+    , uniformVector     -- * References     -- $references     ) where@@ -43,15 +43,15 @@ #endif  import Control.Exception (IOException, catch)-import Control.Monad (ap, unless)-import Control.Monad.ST (ST, runST)-import Data.Array.Vector+import Control.Monad (ap, liftM, unless)+import Control.Monad.Primitive (PrimMonad, PrimState, unsafePrimToIO) import Data.Bits ((.&.), (.|.), xor) import Data.IORef (atomicModifyIORef, newIORef) import Data.Int (Int8, Int16, Int32, Int64) import Data.Ratio ((%), numerator) import Data.Time.Clock.POSIX (getPOSIXTime) import Data.Typeable (Typeable)+import Data.Vector.Generic (Vector, unsafeFreeze) import Data.Word (Word, Word8, Word16, Word32, Word64) import Foreign.Marshal.Alloc (allocaBytes) import Foreign.Marshal.Array (peekArray)@@ -61,6 +61,8 @@ import System.CPUTime (cpuTimePrecision, getCPUTime) import System.IO (IOMode(..), hGetBuf, hPutStrLn, stderr, withBinaryFile) import System.IO.Unsafe (unsafePerformIO)+import qualified Data.Vector.Unboxed as I+import qualified Data.Vector.Unboxed.Mutable as M  -- | The class of types for which we can generate uniformly -- distributed random variates.@@ -72,7 +74,7 @@ -- -- /Note/: Marsaglia's PRNG is not known to be cryptographically -- secure, so you should not use it for cryptographic operations.-class Variate a where+class M.Unbox a => Variate a where     -- | Generate a single uniformly distributed random variate.  The     -- range of values produced varies by type:     --@@ -90,7 +92,7 @@     -- To generate a 'Float' variate with a range of [0,1), subtract     -- 2**(-33).  To do the same with 'Double' variates, subtract     -- 2**(-53).-    uniform :: Gen s -> ST s a+    uniform :: (PrimMonad m) => Gen (PrimState m) -> m a  -- Thanks to Duncan Coutts for finding the pattern below for -- strong-arming GHC 6.10's inliner into behaving itself.  This makes@@ -157,23 +159,25 @@ #endif                       {-# INLINE f #-} +{- instance Variate Integer where     uniform = f where f g = do                            u <- uniform g                            return $! fromIntegral (u :: Int)                       {-# INLINE f #-}+-}  instance (Variate a, Variate b) => Variate (a,b) where-    uniform = f where f g = (,) `fmap` uniform g `ap` uniform g+    uniform = f where f g = (,) `liftM` uniform g `ap` uniform g                       {-# INLINE f #-}  instance (Variate a, Variate b, Variate c) => Variate (a,b,c) where-    uniform = f where f g = (,,) `fmap` uniform g `ap` uniform g `ap` uniform g+    uniform = f where f g = (,,) `liftM` uniform g `ap` uniform g `ap` uniform g                       {-# INLINE f #-}  instance (Variate a, Variate b, Variate c, Variate d) => Variate (a,b,c,d) where     uniform = f-        where f g = (,,,) `fmap` uniform g `ap` uniform g `ap` uniform g+        where f g = (,,,) `liftM` uniform g `ap` uniform g `ap` uniform g                           `ap` uniform g               {-# INLINE f #-} @@ -204,14 +208,14 @@ {-# INLINE wordsToDouble #-}  -- | State of the pseudo-random number generator.-newtype Gen s = Gen (MUArr Word32 s)+newtype Gen s = Gen (M.MVector s Word32)  ioff, coff :: Int ioff = 256 coff = 257  -- | Create a generator for variates using a fixed seed.-create :: ST s (Gen s)+create :: PrimMonad m => m (Gen (PrimState m)) create = initialize defaultSeed {-# INLINE create #-} @@ -229,52 +233,52 @@ -- If a seed contains fewer than 256 elements, it is first used -- verbatim, then its elements are 'xor'ed against elements of the -- default seed until 256 elements are reached.-initialize :: UArr Word32 -> ST s (Gen s)+initialize :: PrimMonad m => I.Vector Word32 -> m (Gen (PrimState m)) initialize seed = do-    q <- newMU 258+    q <- M.unsafeNew 258     fill q-    writeMU q ioff 255-    writeMU q coff 362436+    M.unsafeWrite q ioff 255+    M.unsafeWrite q coff 362436     return (Gen q)   where fill q = go 0 where           go i | i == 256  = return ()-               | otherwise = writeMU q i s >> go (i+1)+               | otherwise = M.unsafeWrite q i s >> go (i+1)             where s | i >= fini = if fini == 0-                                  then indexU defaultSeed i-                                  else indexU defaultSeed i `xor`-                                       indexU seed (i `mod` fini)-                    | otherwise = indexU seed i-        fini = lengthU seed+                                  then I.unsafeIndex defaultSeed i+                                  else I.unsafeIndex defaultSeed i `xor`+                                       I.unsafeIndex seed (i `mod` fini)+                    | otherwise = I.unsafeIndex seed i+        fini = I.length seed {-# INLINE initialize #-}                                 -- | An immutable snapshot of the state of a 'Gen'.-newtype Seed = Seed (UArr Word32)-    deriving (Eq, Read, Show, Typeable)+newtype Seed = Seed (I.Vector Word32)+    deriving (Eq, Show, Typeable)  -- | Save the state of a 'Gen', for later use by 'restore'.-save :: Gen s -> ST s Seed-save (Gen q) = Seed `fmap` unsafeFreezeAllMU q+save :: PrimMonad m => Gen (PrimState m) -> m Seed+save (Gen q) = Seed `liftM` unsafeFreeze q {-# INLINE save #-}  -- | Create a new 'Gen' that mirrors the state of a saved 'Seed'.-restore :: Seed -> ST s (Gen s)-restore (Seed s) = newMU n >>= fill+restore :: PrimMonad m => Seed -> m (Gen (PrimState m))+restore (Seed s) = M.unsafeNew n >>= fill   where fill q = go 0 where-          go !i | i >= n    = return (Gen q)-                | otherwise = writeMU q i (indexU s i) >> go (i+1)-        n = lengthU s+          go !i | i >= n    = return $! Gen q+                | otherwise = M.unsafeWrite q i (I.unsafeIndex s i) >> go (i+1)+        n = I.length s {-# INLINE restore #-}    -- | Using the current time as a seed, perform an action that uses a -- random variate generator.  This is a horrible fallback for Windows -- systems.-withTime :: (forall s. Gen s -> ST s a) -> IO a+withTime :: (PrimMonad m) => (Gen (PrimState m) -> m a) -> IO a withTime act = do-  c <- (numerator . (%cpuTimePrecision)) `fmap` getCPUTime-  t <- toRational `fmap` getPOSIXTime+  c <- (numerator . (%cpuTimePrecision)) `liftM` getCPUTime+  t <- toRational `liftM` getPOSIXTime   let n    = fromIntegral (numerator t) :: Word64       seed = [fromIntegral c, fromIntegral n, fromIntegral (n `shiftR` 32)]-  return . runST $ initialize (toU seed) >>= act+  unsafePrimToIO $ initialize (I.fromList seed) >>= act  -- | Seed a PRNG with data from the system's fast source of -- pseudo-random numbers (\"\/dev\/urandom\" on Unix-like systems),@@ -284,7 +288,7 @@ -- Cryptographic API as a source of random numbers (it uses the system -- clock instead). As a result, the sequences it generates may not be -- highly independent.-withSystemRandom :: (forall s. Gen s -> ST s a) -> IO a+withSystemRandom :: PrimMonad m => (Gen (PrimState m) -> m a) -> IO a withSystemRandom act = tryRandom `catch` \(_::IOException) -> do     seen <- atomicModifyIORef warned ((,) True)     unless seen $ do@@ -298,7 +302,7 @@                   nread <- withBinaryFile random ReadMode $                            \h -> hGetBuf h buf nbytes                   peekArray (nread `div` 4) buf-          return . runST $ initialize (toU ws) >>= act+          unsafePrimToIO $ initialize (I.fromList ws) >>= act         random = "/dev/urandom"         warned = unsafePerformIO $ newIORef False         {-# NOINLINE warned #-}@@ -317,73 +321,75 @@ nextIndex i = fromIntegral j     where j = fromIntegral (i+1) :: Word8 -uniformWord32 :: Gen s -> ST s Word32+uniformWord32 :: PrimMonad m => Gen (PrimState m) -> m Word32 uniformWord32 (Gen q) = do   let a = 809430660 :: Word64-  i <- nextIndex `fmap` readMU q ioff-  c <- fromIntegral `fmap` readMU q coff-  qi <- fromIntegral `fmap` readMU q i+  i <- nextIndex `liftM` M.unsafeRead q ioff+  c <- fromIntegral `liftM` M.unsafeRead q coff+  qi <- fromIntegral `liftM` M.unsafeRead q i   let t   = a * qi + c       t32 = fromIntegral t-  writeMU q i t32-  writeMU q ioff (fromIntegral i)-  writeMU q coff (fromIntegral (t `shiftR` 32))+  M.unsafeWrite q i t32+  M.unsafeWrite q ioff (fromIntegral i)+  M.unsafeWrite q coff (fromIntegral (t `shiftR` 32))   return t32 {-# INLINE uniformWord32 #-} -uniform1 :: (Word32 -> a) -> Gen s -> ST s a+uniform1 :: PrimMonad m => (Word32 -> a) -> Gen (PrimState m) -> m a uniform1 f gen = do   i <- uniformWord32 gen   return $! f i {-# INLINE uniform1 #-} -uniform2 :: (Word32 -> Word32 -> a) -> Gen s -> ST s a+uniform2 :: PrimMonad m => (Word32 -> Word32 -> a) -> Gen (PrimState m) -> m a uniform2 f (Gen q) = do   let a = 809430660 :: Word64-  i <- nextIndex `fmap` readMU q ioff+  i <- nextIndex `liftM` M.unsafeRead q ioff   let j = nextIndex i-  c <- fromIntegral `fmap` readMU q coff-  qi <- fromIntegral `fmap` readMU q i-  qj <- fromIntegral `fmap` readMU q j+  c <- fromIntegral `liftM` M.unsafeRead q coff+  qi <- fromIntegral `liftM` M.unsafeRead q i+  qj <- fromIntegral `liftM` M.unsafeRead q j   let t   = a * qi + c       t32 = fromIntegral t       c'  = t `shiftR` 32       u   = a * qj + c'       u32 = fromIntegral u-  writeMU q i t32-  writeMU q j u32-  writeMU q ioff (fromIntegral j)-  writeMU q coff (fromIntegral (u `shiftR` 32))+  M.unsafeWrite q i t32+  M.unsafeWrite q j u32+  M.unsafeWrite q ioff (fromIntegral j)+  M.unsafeWrite q coff (fromIntegral (u `shiftR` 32))   return $! f t32 u32 {-# INLINE uniform2 #-} --- | Generate an array of pseudo-random variates.  This is not+-- | Generate a vector of pseudo-random variates.  This is not -- necessarily faster than invoking 'uniform' repeatedly in a loop, -- but it may be more convenient to use in some situations.-uniformArray :: (UA a, Variate a) => Gen s -> Int -> ST s (UArr a)-uniformArray gen n = newMU n >>= loop+uniformVector :: (PrimMonad m, Variate a)+             => Gen (PrimState m) -> Int -> m (I.Vector a)+uniformVector gen n = M.unsafeNew n >>= go (uniform gen) 0   where-    loop mu = go 0-      where go !i | i >= n    = unsafeFreezeAllMU mu-                  | otherwise = uniform gen >>= writeMU mu i >> go (i+1)-{-# INLINE uniformArray #-}+    go u !i mu | i >= n    = unsafeFreeze mu+               | otherwise = u >>= M.unsafeWrite mu i >> go u (i+1) mu+{-# INLINE uniformVector #-} +data T = T {-# UNPACK #-} !Double {-# UNPACK #-} !Double+ -- | Generate a normally distributed random variate. -- -- The implementation uses Doornik's modified ziggurat algorithm. -- Compared to the ziggurat algorithm usually used, this is slower, -- but generates more independent variates that pass stringent tests -- of randomness.-normal :: Gen s -> ST s Double+normal :: PrimMonad m => Gen (PrimState m) -> m Double normal gen = loop   where     loop = do-      u  <- (subtract 1 . (*2)) `fmap` uniform gen+      u  <- (subtract 1 . (*2)) `liftM` uniform gen       ri <- uniform gen       let i  = fromIntegral ((ri :: Word32) .&. 127)-          bi = indexU blocks i-          bj = indexU blocks (i+1)-      if abs u < indexU ratios i+          bi = I.unsafeIndex blocks i+          bj = I.unsafeIndex blocks (i+1)+      if abs u < I.unsafeIndex ratios i         then return $! u * bi         else if i == 0         then normalTail (u < 0)@@ -397,23 +403,26 @@             then return x             else loop     blocks = let f = exp (-0.5 * r * r)-             in (`snocU` 0) . consU (v/f) . consU r . unfoldU 126 go $ (r :*: f)+             in (`I.snoc` 0) . I.cons (v/f) . I.cons r . I.take 126 .+                I.unfoldr go $! T r f       where-        go (b :*: g) = JustS (h :*: (h :*: exp (-0.5 * h * h)))-          where h    = sqrt (-2 * log (v / b + g))+        go (T b g)   = let !u = T h (exp (-0.5 * h * h))+                           h  = sqrt (-2 * log (v / b + g))+                       in Just (h, u)         v            = 9.91256303526217e-3     r                = 3.442619855899-    ratios           = zipWithU (/) (tailU blocks) blocks+    ratios           = I.zipWith (/) (I.tail blocks) blocks     normalTail neg   = tailing       where tailing  = do-              x <- ((/r) . log) `fmap` uniform gen-              y <- log          `fmap` uniform gen+              x <- ((/r) . log) `liftM` uniform gen+              y <- log          `liftM` uniform gen               if y * (-2) < x * x                 then tailing                 else return $! if neg then x - r else r - x+{-# INLINE normal #-} -defaultSeed :: UArr Word32-defaultSeed = toU [+defaultSeed :: I.Vector Word32+defaultSeed = I.fromList [   0x7042e8b3, 0x06f7f4c5, 0x789ea382, 0x6fb15ad8, 0x54f7a879, 0x0474b184,   0xb3f8f692, 0x4114ea35, 0xb6af0230, 0xebb457d2, 0x47693630, 0x15bc0433,   0x2e1e5b18, 0xbe91129c, 0xcc0815a0, 0xb1260436, 0xd6f605b1, 0xeaadd777,
mwc-random.cabal view
@@ -1,5 +1,5 @@ name:           mwc-random-version:        0.4.1.1+version:        0.5.0.0 synopsis:       Fast, high quality pseudo random number generation description:   This package contains code for generating high quality random@@ -19,7 +19,7 @@ homepage:       http://darcs.serpentine.com/mwc-random author:         Bryan O'Sullivan <bos@serpentine.com> maintainer:     Bryan O'Sullivan <bos@serpentine.com>-copyright:      2009 Bryan O'Sullivan+copyright:      2009, 2010 Bryan O'Sullivan category:       Math, Statistics build-type:     Simple cabal-version:  >= 1.2@@ -30,8 +30,9 @@     System.Random.MWC   build-depends:     base < 5,+    primitive,     time,-    uvector >= 0.1.0.4+    vector >= 0.5   if impl(ghc >= 6.10)     build-depends:       base >= 4