packages feed

mwc-random 0.11.0.0 → 0.12.0.0

raw patch · 8 files changed

+433/−45 lines, 8 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ System.Random.MWC: asGenIO :: (GenIO -> IO a) -> (GenIO -> IO a)
+ System.Random.MWC: asGenST :: (GenST s -> ST s a) -> (GenST s -> ST s a)
+ System.Random.MWC.CondensedTable: data CondensedTable v a
+ System.Random.MWC.CondensedTable: genFromTable :: (PrimMonad m, Vector v a) => CondensedTable v a -> Gen (PrimState m) -> m a
+ System.Random.MWC.CondensedTable: tableBinomial :: Int -> Double -> CondensedTableU Int
+ System.Random.MWC.CondensedTable: tableFromIntWeights :: (Vector v (a, Word32), Vector v a, Vector v Word32) => v (a, Word32) -> CondensedTable v a
+ System.Random.MWC.CondensedTable: tableFromProbabilities :: (Vector v (a, Word32), Vector v (a, Double), Vector v a, Vector v Word32) => v (a, Double) -> CondensedTable v a
+ System.Random.MWC.CondensedTable: tableFromWeights :: (Vector v (a, Word32), Vector v (a, Double), Vector v a, Vector v Word32) => v (a, Double) -> CondensedTable v a
+ System.Random.MWC.CondensedTable: tablePoisson :: Double -> CondensedTableU Int
+ System.Random.MWC.CondensedTable: type CondensedTableU = CondensedTable Vector
+ System.Random.MWC.CondensedTable: type CondensedTableV = CondensedTable Vector

Files

README.markdown view
@@ -5,29 +5,6 @@ time-efficient way.  -# Performance--This library has been carefully optimised for high performance.  To-obtain the best runtime efficiency, it is imperative to compile-libraries and applications that use this library using a high level of-optimisation.--Suggested GHC options:--    -O -fvia-C -funbox-strict-fields--To illustrate, here are the times (in seconds) to generate and sum 250-million random Word32 values, on a laptop with a 2.4GHz Core2 Duo-P8600 processor, running Fedora 11 and GHC 6.10.3:--    no flags   200+-    -O           1.249-    -O -fvia-C   0.991--As the numbers above suggest, compiling without optimisation will-yield unacceptable performance.-- # Get involved!  Please report bugs via the
System/Random/MWC.hs view
@@ -37,19 +37,23 @@ -- The simplest use is to generate a vector of uniformly distributed values: -- -- @---   vs <- withSystemRandom (uniformVector 100)+--   vs <- withSystemRandom . asGenST $ \gen -> uniformVector gen 100 -- @ ----- These values can be of any type which is an instance of the class 'Variate'.+-- These values can be of any type which is an instance of the class+-- 'Variate'. ----- To generate random values on demand, first 'create' a random number generator.+-- To generate random values on demand, first 'create' a random number+-- generator. -- -- @ --   gen <- create -- @ ----- Keep this generator and use it wherever random values are required. Get a random--- value using 'uniform' or 'uniformR':+-- Hold onto this generator and use it wherever random values are+-- required (creating a new generator is expensive compared to+-- generating a random number, so you don't want to throw them+-- away). Get a random value using 'uniform' or 'uniformR': -- -- @ --   v <- uniform gen@@ -62,12 +66,17 @@     (     -- * Gen: Pseudo-Random Number Generators       Gen-    , GenIO-    , GenST     , create     , initialize     , withSystemRandom +    -- ** Type helpers+    -- $typehelp+    , GenIO+    , GenST+    , asGenIO+    , asGenST+     -- * Variates: uniformly distributed values     , Variate(..)     , uniformVector@@ -294,12 +303,20 @@ -- | State of the pseudo-random number generator. newtype Gen s = Gen (M.MVector s Word32) --- | A shorter name for PRNG state in the IO monad.+-- | A shorter name for PRNG state in the 'IO' monad. type GenIO = Gen (PrimState IO) --- | A shorter name for PRNG state in the ST monad.+-- | A shorter name for PRNG state in the 'ST' monad. type GenST s = Gen (PrimState (ST s)) +-- | Constrain the type of an action to run in the 'IO' monad.+asGenIO :: (GenIO -> IO a) -> (GenIO -> IO a)+asGenIO = id++-- | Constrain the type of an action to run in the 'ST' monad.+asGenST :: (GenST s -> ST s a) -> (GenST s -> ST s a)+asGenST = id+ ioff, coff :: Int ioff = 256 coff = 257@@ -389,7 +406,7 @@   let n    = fromIntegral (numerator t) :: Word64   return [fromIntegral c, fromIntegral n, fromIntegral (n `shiftR` 32)] --- Aquire seed from /dev/urandom+-- | Acquire seed from /dev/urandom acquireSeedSystem :: IO [Word32] acquireSeedSystem = do   let nbytes = 1024@@ -400,12 +417,12 @@     peekArray (nread `div` 4) buf    -- | Seed a PRNG with data from the system's fast source of--- pseudo-random numbers (\"\/dev\/urandom\" on Unix-like systems),+-- pseudo-random numbers (\"@\/dev\/urandom@\" on Unix-like systems), -- then run the given action. ----- This is a heavyweight function, intended to be called only--- occasionally (e.g. once per thread).  You should use the `Gen` it--- creates to generate many random numbers.+-- This is a somewhat expensive function, and is intended to be called+-- only occasionally (e.g. once per thread).  You should use the `Gen`+-- it creates to generate many random numbers. -- -- /Note/: on Windows, this code does not yet use the native -- Cryptographic API as a source of random numbers (it uses the system@@ -601,3 +618,43 @@ --   (2007). Gaussian random number generators. --   /ACM Computing Surveys/ 39(4). --   <http://www.cse.cuhk.edu.hk/~phwl/mt/public/archives/papers/grng_acmcs07.pdf>++-- $typehelp+--+-- The functions in this package are deliberately written for+-- flexibility, and will run in both the 'IO' and 'ST' monads.+--+-- This can defeat the compiler's ability to infer a principal type in+-- simple (and common) cases.  For instance, we would like the+-- following to work cleanly:+--+-- > import System.Random.MWC+-- > import Data.Vector.Unboxed+-- >+-- > main = do+-- >   v <- withSystemRandom $ \gen -> uniformVector gen 20+-- >   print (v :: Vector Int)+--+-- Unfortunately, the compiler cannot tell what monad 'uniformVector'+-- should execute in.  The \"fix\" of adding explicit type annotations+-- is not pretty:+--+-- > {-# LANGUAGE ScopedTypeVariables #-}+-- >+-- > import Control.Monad.ST+-- >+-- > main = do+-- >   vs <- withSystemRandom $+-- >         \(gen::GenST s) -> uniformVector gen 20 :: ST s (Vector Int)+-- >   print vs+--+-- As a more readable alternative, this library provides 'asGenST' and+-- 'asGenIO' to constrain the types appropriately.  We can get rid of+-- the explicit type annotations as follows:+--+-- > main = do+-- >   vs <- withSystemRandom . asGenST $ \gen -> uniformVector gen 20+-- >   print (vs :: Vector Int)+--+-- This is almost as compact as the original code that the compiler+-- rejected.
+ System/Random/MWC/CondensedTable.hs view
@@ -0,0 +1,269 @@+{-# LANGUAGE FlexibleContexts #-}+-- |+-- Module    : System.Random.MWC.CondensedTable+-- Copyright : (c) 2012 Aleksey Khudyakov+-- License   : BSD3+--+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : portable+--+-- Table-driven generation of random variates.  This approach can+-- generate random variates in /O(1)/ time for the supported+-- distributions, at a modest cost in initialization time.+module System.Random.MWC.CondensedTable (+    -- * Condensed tables+    CondensedTable+  , CondensedTableV+  , CondensedTableU+  , genFromTable+    -- * Constructors for tables+  , tableFromProbabilities+  , tableFromWeights+  , tableFromIntWeights+    -- ** Disrete distributions+  , tablePoisson+  , tableBinomial+  ) where++import Control.Arrow           (second,(***))+import Control.Monad.Primitive (PrimMonad(..))++import Data.Word+import Data.Int+import Data.Bits+import qualified Data.Vector.Generic         as G+import           Data.Vector.Generic           ((++))+import qualified Data.Vector.Generic.Mutable as M+import qualified Data.Vector.Unboxed         as U+import qualified Data.Vector                 as V+import Data.Vector.Generic (Vector)++import Prelude hiding ((++))++import System.Random.MWC++++-- | A lookup table for arbitrary discrete distributions. It allows+-- the generation of random variates in /O(1)/. Note that probability+-- is quantized in units of @1/2^32@, and all distributions with+-- infinite support (e.g. Poisson) should be truncated.+data CondensedTable v a =+  CondensedTable+  {-# UNPACK #-} !Word64 !(v a) -- Lookup limit and first table+  {-# UNPACK #-} !Word64 !(v a) -- Second table+  {-# UNPACK #-} !Word64 !(v a) -- Third table+  !(v a)                        -- Last table++-- Implementation note. We have to store lookup limit in Word64 since+-- we need to accomodate two cases. First is when we have no values in+-- lookup table, second is when all elements are there+--+-- Both are pretty easy to realize. For first one probability of every+-- outcome should be less then 1/256, latter arise when probabilities+-- of two outcomes are [0.5,0.5]++-- | A 'CondensedTable' that uses unboxed vectors.+type CondensedTableU = CondensedTable U.Vector++-- | A 'CondensedTable' that uses boxed vectors, and is able to hold+-- any type of element.+type CondensedTableV = CondensedTable V.Vector++++-- | Generate a random value using a condensed table.+genFromTable :: (PrimMonad m, Vector v a) =>+                CondensedTable v a -> Gen (PrimState m) -> m a+{-# INLINE genFromTable #-}+genFromTable table gen = do+  w <- uniform gen+  return $ lookupTable table $ fromIntegral (w :: Word32)++lookupTable :: Vector v a => CondensedTable v a -> Word64 -> a+{-# INLINE lookupTable #-}+lookupTable (CondensedTable na aa nb bb nc cc dd) i+  | i < na    = aa `at` ( i       `shiftR` 24)+  | i < nb    = bb `at` ((i - na) `shiftR` 16)+  | i < nc    = cc `at` ((i - nb) `shiftR` 8 )+  | otherwise = dd `at` ( i - nc)+  where+    at arr j = G.unsafeIndex arr (fromIntegral j)+++----------------------------------------------------------------+-- Table generation+----------------------------------------------------------------++-- | Generate a condensed lookup table from a list of outcomes with+-- given probabilities. The vector should be non-empty and the+-- probabilites should be non-negative and sum to 1. If this is not+-- the case, this algorithm will construct a table for some+-- distribution that may bear no resemblance to what you intended.+tableFromProbabilities+    :: (Vector v (a,Word32), Vector v (a,Double), Vector v a, Vector v Word32)+       => v (a, Double) -> CondensedTable v a+{-# INLINE tableFromProbabilities #-}+tableFromProbabilities v+  | G.null v  = pkgError "tableFromProbabilities" "empty vector of outcomes"+  | otherwise = tableFromIntWeights $ G.map (second $ round . (* mlt)) v+  where+    mlt = 4.294967296e9 -- 2^32++-- | Same as 'tableFromProbabilities' but treats number as weights not+-- probilities. Non-positive weights are discarded, and those+-- remaining are normalized to 1.+tableFromWeights+    :: (Vector v (a,Word32), Vector v (a,Double), Vector v a, Vector v Word32)+       => v (a, Double) -> CondensedTable v a+{-# INLINE tableFromWeights #-}+tableFromWeights = tableFromProbabilities . normalize . G.filter ((> 0) . snd)+  where+    normalize v+      | G.null v  = pkgError "tableFromWeights" "no positive weights"+      | otherwise = G.map (second (/ s)) v+      where+        -- Explicit fold is to avoid 'Vector v Double' constraint+        s = G.foldl' (flip $ (+) . snd) 0 v+++-- | Generate a condensed lookup table from integer weights. Weights+-- should sum to @2^32@. If they don't, the algorithm will alter the+-- weights so that they do. This approach should work reasonably well+-- for rounding error.+tableFromIntWeights :: (Vector v (a,Word32), Vector v a, Vector v Word32)+                    => v (a, Word32)+                    -> CondensedTable v a+{-# INLINE tableFromIntWeights #-}+tableFromIntWeights tbl+  | n == 0    = pkgError "tableFromIntWeights" "empty table"+    -- Single element tables should be treated sepately. Otherwise+    -- they will confuse correctWeights+  | n == 1    = let m = 2^(32::Int) - 1 -- Works for both Word32 & Word64+                in CondensedTable+                   m (G.replicate 256 $ fst $ G.head tbl)+                   m  G.empty+                   m  G.empty+                      G.empty+  | otherwise = CondensedTable+                na aa+                nb bb+                nc cc+                   dd+  where+    n     = G.length tbl+    -- Corrected table+    table = uncurry G.zip $ id *** correctWeights $ G.unzip tbl+    -- Make condensed table+    mkTable  d =+      G.concatMap (\(x,w) -> G.replicate (fromIntegral $ digit d w) x) table+    len = fromIntegral . G.length+    -- Tables+    aa = mkTable 0+    bb = mkTable 1+    cc = mkTable 2+    dd = mkTable 3+    -- Offsets+    na =       len aa `shiftL` 24+    nb = na + (len bb `shiftL` 16)+    nc = nb + (len cc `shiftL` 8)+++-- Calculate N'th digit base 256+digit :: Int -> Word32 -> Word32+digit 0 x =  x `shiftR` 24+digit 1 x = (x `shiftR` 16) .&. 0xff+digit 2 x = (x `shiftR` 8 ) .&. 0xff+digit 3 x =  x .&. 0xff+digit _ _ = pkgError "digit" "the impossible happened!?"+{-# INLINE digit #-}++-- Correct integer weights so they sum up to 2^32. Array of weight+-- should contain at least 2 elements.+correctWeights :: G.Vector v Word32 => v Word32 -> v Word32+{-# INLINE correctWeights #-}+correctWeights v = G.create $ do+  let+    -- Sum of weights+    s = G.foldl' (flip $ (+) . fromIntegral) 0 v :: Int64+    -- Array size+    n = G.length v+  arr <- G.thaw v+  -- On first pass over array adjust only entries which are larger+  -- than `lim'. On second and subsequent passes `lim' is set to 1.+  --+  -- It's possibly to make this algorithm loop endlessly if all+  -- weights are 1 or 0.+  let loop lim i delta+        | delta == 0 = return ()+        | i >= n     = loop 1 0 delta+        | otherwise  = do+            w <- M.read arr i+            case () of+              _| w < lim   -> loop lim (i+1) delta+               | delta < 0 -> M.write arr i (w + 1) >> loop lim (i+1) (delta + 1)+               | otherwise -> M.write arr i (w - 1) >> loop lim (i+1) (delta - 1)+  loop 255 0 (s - 2^(32::Int))+  return arr+++-- | Create a lookup table for the Poisson distibution. Note that+-- table construction may have significant cost. For &#955; < 100 it+-- takes as much time to build table as generation of 1000-30000+-- variates.+tablePoisson :: Double -> CondensedTableU Int+tablePoisson = tableFromProbabilities . make+  where+    make lam+      | lam < 0    = pkgError "tablePoisson" "negative lambda"+      | lam < 22.8 = U.unfoldr unfoldForward (exp (-lam), 0)+      | otherwise  = U.unfoldr unfoldForward (pMax, nMax)+                  ++ U.tail (U.unfoldr unfoldBackward (pMax, nMax))+      where+        -- Number with highest probability and its probability+        nMax = floor lam :: Int+        pMax = let c = lam * exp( -lam / fromIntegral nMax )+               in  U.foldl' (\p i -> p * c / i) 1 (U.enumFromN 1 nMax)+        -- Build probability list+        unfoldForward (p,i)+          | p < minP  = Nothing+          | otherwise = Just ( (i,p)+                             , (p * lam / fromIntegral (i+1), i+1)+                             )+        -- Go down+        unfoldBackward (p,i)+          | p < minP  = Nothing+          | otherwise = Just ( (i,p)+                             , (p / lam * fromIntegral i, i-1)+                             )+    minP = 1.1641532182693481e-10 -- 2**(-33)++-- | Create a lookup table for the binomial distribution.+tableBinomial :: Int            -- ^ Number of tries+              -> Double         -- ^ Probability of success+              -> CondensedTableU Int+tableBinomial n p = tableFromProbabilities makeBinom+  where +  makeBinom+    | n <= 0         = pkgError "tableBinomial" "non-positive number of tries"+    | p == 0         = U.singleton (0,1)+    | p == 1         = U.singleton (n,1)+    | p > 0 && p < 1 = U.unfoldrN (n + 1) unfolder ((1-p)^n, 0)+    | otherwise      = pkgError "tableBinomial" "probability is out of range"+    where+      h = p / (1 - p)+      unfolder (t,i) = Just ( (i,t)+                            , (t * (fromIntegral $ n + 1 - i1) * h / fromIntegral i1, i1) )+        where i1 = i + 1++pkgError :: String -> String -> a+pkgError func err =+    error . concat $ ["System.Random.MWC.CondensedTable.", func, ": ", err]++-- $references+--+-- * Wang, J.; Tsang, W. W.; G. Marsaglia (2004), Fast Generation of+--   Discrete Random Variables, /Journal of Statistical Software,+--   American Statistical Association/, vol. 11(i03).+--   <http://ideas.repec.org/a/jss/jstsof/11i03.html>
System/Random/MWC/Distributions.hs view
@@ -95,7 +95,7 @@                 else return $! if neg then x - r else r - x  --- | Generate exponentially distributed random variate.+-- | Generate an exponentially distributed random variate. exponential :: PrimMonad m             => Double            -- ^ Scale parameter             -> Gen (PrimState m) -- ^ Generator@@ -139,7 +139,7 @@       a2 = 1 / sqrt(9 * a1)  --- | Random variate generator for chi square distribution.+-- | Random variate generator for the chi square distribution. chiSquare :: PrimMonad m           => Int                -- ^ Number of degrees of freedom           -> Gen (PrimState m)  -- ^ Generator
benchmarks/Benchmark.hs view
@@ -3,15 +3,23 @@ import Criterion.Main import Data.Int import Data.Word+import qualified Data.Vector.Unboxed as U import qualified System.Random as R import System.Random.MWC import System.Random.MWC.Distributions+import System.Random.MWC.CondensedTable import qualified System.Random.Mersenne as M +makeTableUniform :: Int -> CondensedTable U.Vector Int+makeTableUniform n =+  tableFromProbabilities $ U.zip (U.enumFromN 0 n) (U.replicate n (1 / fromIntegral n))+{-# INLINE makeTableUniform #-}++ main = do   mwc <- create   mtg <- M.newMTGen . Just =<< uniform mwc-  defaultMain +  defaultMain     [ bgroup "mwc"       -- One letter group names are used so they will fit on the plot.       --@@ -53,6 +61,28 @@         , bench "gamma,a<1"   (gamma 0.5 1   mwc :: IO Double)         , bench "gamma,a>1"   (gamma 2   1   mwc :: IO Double)         , bench "chiSquare"   (chiSquare 4   mwc :: IO Double)+        ]+      , bgroup "CT/gen" $ concat+        [ [ bench ("uniform "++show i)     (genFromTable (makeTableUniform i) mwc :: IO Int)+          | i <- [2..10]+          ]+        , [ bench ("poisson " ++ show l)   (genFromTable (tablePoisson l) mwc :: IO Int)+          | l <- [0.01, 0.2, 0.8, 1.3, 2.4, 8, 12, 100, 1000]+          ]+        , [ bench ("binomial " ++ show p ++ " " ++ show n) (genFromTable (tableBinomial n p) mwc :: IO Int)+          | (n,p) <- [ (4, 0.5), (10,0.1), (10,0.6), (10, 0.8), (100,0.4)]+          ]+        ]+      , bgroup "CT/table" $ concat+        [ [ bench ("uniform " ++ show i) $ whnf makeTableUniform i+          | i <- [2..30]+          ]+        , [ bench ("poisson " ++ show l) $ whnf tablePoisson l+          | l <- [0.01, 0.2, 0.8, 1.3, 2.4, 8, 12, 100, 1000]+          ]+        , [ bench ("binomial " ++ show p ++ " " ++ show n) $ whnf (tableBinomial n) p+          | (n,p) <- [ (4, 0.5), (10,0.1), (10,0.6), (10, 0.8), (100,0.4)]+          ]         ]       ]     , bgroup "random"
mwc-random.cabal view
@@ -1,5 +1,5 @@ name:           mwc-random-version:        0.11.0.0+version:        0.12.0.0 synopsis:       Fast, high quality pseudo random number generation description:   This package contains code for generating high quality random@@ -37,6 +37,7 @@   exposed-modules:     System.Random.MWC     System.Random.MWC.Distributions+    System.Random.MWC.CondensedTable   build-depends:     base < 5,     primitive,
test/visual.R view
@@ -3,13 +3,28 @@   view.dumps <- function() {+  # Load random data from dist   load.d <- function(name) read.table(name)[,1]+  # Plots for continous distribution   plot.d <- function(name, dens, rng) {     smp <- load.d( name )     plot( density(smp), xlim=rng, main=name, col='blue', lwd=2)     hist( smp, probability=TRUE, breaks=100, add=TRUE)     plot( dens, xlim=rng, col='red', add=TRUE, lwd=2)   }+  # plots for discrete distribution+  plot.ds <- function( name, xs, prob) {+    smp <- load.d( name )+    h   <- hist( smp,+                 breaks = c( max(xs) + 0.5, xs - 0.5),+                 freq=FALSE, main = name+                )+    dh  <- sqrt( h$count ) / max( 1, sum( h$count ) )+    arrows( xs, h$density + dh,+            xs, h$density - dh,+            angle=90, code=3, length=0.2 )+    points( xs, prob(xs), pch='0', col='red', type='b')+  }   ################################################################   # Normal   plot.d ("distr/normal-0-1",@@ -59,4 +74,32 @@           function(x) dexp(x,3),           c(-0.5, 3) )   readline()+  ################################################################+  # Poisson+  plot.ds( "distr/poisson-0.1", 0:6, function(x) dpois(x, lambda=0.1) )+  readline()+  #+  plot.ds( "distr/poisson-1.0", 0:10, function(x) dpois(x, lambda=1.0) )+  readline()+  #+  plot.ds( "distr/poisson-4.5", 0:20, function(x) dpois(x, lambda=4.5) )+  readline()+  #+  plot.ds( "distr/poisson-30", 0:100, function(x) dpois(x, lambda=30) )+  readline()+  #+  ################################################################+  # Binomial+  plot.ds( "distr/binom-4-0.5", 0:4, function(x) dbinom(x, 4, 0.5) )+  readline()+  #+  plot.ds( "distr/binom-10-0.1", 0:10, function(x) dbinom(x, 10, 0.1) )+  readline()+  #+  plot.ds( "distr/binom-10-0.6", 0:10, function(x) dbinom(x, 10, 0.6) )+  readline()+  #+  plot.ds( "distr/binom-10-0.8", 0:10, function(x) dbinom(x, 10, 0.8) )+  readline()+  # }
test/visual.hs view
@@ -4,18 +4,19 @@ import System.Directory  (createDirectoryIfMissing,setCurrentDirectory) import System.IO -import qualified System.Random.MWC               as MWC-import qualified System.Random.MWC.Distributions as MWC+import qualified System.Random.MWC                as MWC+import qualified System.Random.MWC.Distributions  as MWC+import qualified System.Random.MWC.CondensedTable as MWC   dumpSample :: Show a => Int -> FilePath -> IO a -> IO () dumpSample n fname gen =   withFile fname WriteMode $ \h ->      replicateM_ n (hPutStrLn h . show =<< gen)-  + main :: IO () main = MWC.withSystemRandom $ \g -> do-  let n   = 10000+  let n   = 30000       dir = "distr"   createDirectoryIfMissing True dir   setCurrentDirectory           dir@@ -31,3 +32,13 @@   -- Exponential   dumpSample n "exponential-1" $ MWC.exponential 1 g   dumpSample n "exponential-3" $ MWC.exponential 3 g+  -- Poisson+  dumpSample n "poisson-0.1"   $ MWC.genFromTable (MWC.tablePoisson 0.1) g+  dumpSample n "poisson-1.0"   $ MWC.genFromTable (MWC.tablePoisson 1.0) g+  dumpSample n "poisson-4.5"   $ MWC.genFromTable (MWC.tablePoisson 4.5) g+  dumpSample n "poisson-30"    $ MWC.genFromTable (MWC.tablePoisson 30)  g+  -- Binomial+  dumpSample n "binom-4-0.5"   $ MWC.genFromTable (MWC.tableBinomial 4  0.5) g+  dumpSample n "binom-10-0.1"  $ MWC.genFromTable (MWC.tableBinomial 10 0.1) g  +  dumpSample n "binom-10-0.6"  $ MWC.genFromTable (MWC.tableBinomial 10 0.6) g+  dumpSample n "binom-10-0.8"  $ MWC.genFromTable (MWC.tableBinomial 10 0.8) g