Skip to content

Commit

Permalink
Finish transition to random-1.2 and mwc-random-0.15. Remove usage…
Browse files Browse the repository at this point in the history
… of `random-source`.

Bump up major versions and update changelog
  • Loading branch information
lehins committed Apr 6, 2021
1 parent 268e66b commit 82d8fb1
Show file tree
Hide file tree
Showing 18 changed files with 350 additions and 279 deletions.
4 changes: 4 additions & 0 deletions random-fu/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
* Chnages in 0.3.0.0:

* Drop usage of `random-source` in favor of `random`

* Changes in 0.2.7.7: Update to random-1.2. Revert 0.2.7.6 changes (which added an extra constraint to `Data.Random.Sample.sampleState` and `Data.Random.Sample.sampleStateT`).

* Changes in 0.2.7.4: Compatibility with ghc 8.8.
Expand Down
19 changes: 9 additions & 10 deletions random-fu/random-fu.cabal
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: random-fu
version: 0.2.7.7
version: 0.3.0.0
stability: provisional

cabal-version: >= 1.10
Expand All @@ -12,21 +12,21 @@ homepage: https://github.com/mokus0/random-fu

category: Math
synopsis: Random number generation
description: Random number generation based on modeling random
description: Random number generation based on modeling random
variables in two complementary ways: first, by the
parameters of standard mathematical distributions and,
second, by an abstract type ('RVar') which can be
composed and manipulated monadically and sampled in
either monadic or \"pure\" styles.
.
The primary purpose of this library is to support
The primary purpose of this library is to support
defining and sampling a wide variety of high quality
random variables. Quality is prioritized over speed,
but performance is an important goal too.
.
In my testing, I have found it capable of speed
In my testing, I have found it capable of speed
comparable to other Haskell libraries, but still
a fair bit slower than straight C implementations of
a fair bit slower than straight C implementations of
the same algorithms.

tested-with: GHC == 7.10.3
Expand Down Expand Up @@ -83,25 +83,24 @@ Library
else
cpp-options: -Dold_Fixed
build-depends: base >= 4 && <4.2

if flag(mtl2)
build-depends: mtl == 2.*
cpp-options: -DMTL2
else
build-depends: mtl == 1.*

build-depends: math-functions,
monad-loops >= 0.3.0.1,
random >= 1.2 && < 1.3,
random-shuffle,
random-source == 0.3.*,
rvar == 0.2.*,
rvar >= 0.3,
syb,
template-haskell,
transformers,
vector >= 0.7,
erf

if impl(ghc == 7.2.1)
-- Doesn't work under GHC 7.2.1 due to
-- http://hackage.haskell.org/trac/ghc/ticket/5410
Expand Down
55 changes: 25 additions & 30 deletions random-fu/src/Data/Random.hs
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
-- |Flexible modeling and sampling of random variables.
--
-- The central abstraction in this library is the concept of a random
-- variable. It is not fully formalized in the standard measure-theoretic
-- language, but rather is informally defined as a \"thing you can get random
-- values out of\". Different random variables may have different types of
-- The central abstraction in this library is the concept of a random
-- variable. It is not fully formalized in the standard measure-theoretic
-- language, but rather is informally defined as a \"thing you can get random
-- values out of\". Different random variables may have different types of
-- values they can return or the same types but different probabilities for
-- each value they can return. The random values you get out of them are
-- traditionally called \"random variates\".
--
-- Most imperative-language random number libraries are all about obtaining
-- and manipulating random variates. This one is about defining, manipulating
-- and sampling random variables. Computationally, the distinction is small
-- and mostly just a matter of perspective, but from a program design
--
-- Most imperative-language random number libraries are all about obtaining
-- and manipulating random variates. This one is about defining, manipulating
-- and sampling random variables. Computationally, the distinction is small
-- and mostly just a matter of perspective, but from a program design
-- perspective it provides both a powerfully composable abstraction and a
-- very useful separation of concerns.
--
--
-- Abstract random variables as implemented by 'RVar' are composable. They can
-- be defined in a monadic / \"imperative\" style that amounts to manipulating
-- variates, but with strict type-level isolation. Concrete random variables
-- are also provided, but they do not compose as generically. The 'Distribution'
-- type class allows concrete random variables to \"forget\" their concreteness
-- so that they can be composed. For examples of both, see the documentation
-- for 'RVar' and 'Distribution', as well as the code for any of the concrete
-- type class allows concrete random variables to \"forget\" their concreteness
-- so that they can be composed. For examples of both, see the documentation
-- for 'RVar' and 'Distribution', as well as the code for any of the concrete
-- distributions such as 'Uniform', 'Gamma', etc.
--
--
-- Both abstract and concrete random variables can be sampled (despite the
-- types GHCi may list for the functions) by the functions in "Data.Random.Sample".
--
--
-- Random variable sampling is done with regard to a generic basis of primitive
-- random variables defined in "Data.Random.Internal.Primitives". This basis
-- random variables defined in "Data.Random.Internal.Primitives". This basis
-- is very low-level and the actual set of primitives is still fairly experimental,
-- which is why it is in the \"Internal\" sub-heirarchy. User-defined variables
-- should use the existing high-level variables such as 'Uniform' and 'Normal'
-- rather than these basis variables. "Data.Random.Source" defines classes for
-- entropy sources that provide implementations of these primitive variables.
-- entropy sources that provide implementations of these primitive variables.
-- Several implementations are available in the Data.Random.Source.* modules.
module Data.Random
( -- * Random variables
Expand All @@ -43,32 +43,26 @@ module Data.Random

-- ** Concrete ('Distribution')
Distribution(..), CDF(..), PDF(..),

-- * Sampling random variables
Sampleable(..), sample, sampleState, sampleStateT,
Sampleable(..), sample, sampleState, samplePure,

-- * A few very common distributions
Uniform(..), uniform, uniformT,
StdUniform(..), stdUniform, stdUniformT,
Normal(..), normal, stdNormal, normalT, stdNormalT,
Gamma(..), gamma, gammaT,

-- * Entropy Sources
MonadRandom, RandomSource, StdRandom(..),
StatefulGen, RandomGen,

-- * Useful list-based operations
randomElement,
shuffle, shuffleN, shuffleNofM

) where

import Data.Random.Sample
import Data.Random.Source (MonadRandom, RandomSource)
import Data.Random.Source.IO ()
import Data.Random.Source.MWC ()
import Data.Random.Source.StdGen ()
import Data.Random.Source.PureMT ()
import Data.Random.Source.Std
import Data.Random.Distribution
import Data.Random.Distribution.Gamma
import Data.Random.Distribution.Normal
Expand All @@ -78,3 +72,4 @@ import Data.Random.Lift ()
import Data.Random.List
import Data.Random.RVar

import System.Random.Stateful (StatefulGen, RandomGen)
2 changes: 0 additions & 2 deletions random-fu/src/Data/Random/Distribution/Categorical.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ import Data.Random.Distribution.Uniform
import Control.Arrow
import Control.Monad
import Control.Monad.ST
import Data.Foldable (Foldable(foldMap))
import Data.STRef
import Data.Traversable (Traversable(traverse, sequenceA))

import Data.List
import Data.Function
Expand Down
39 changes: 34 additions & 5 deletions random-fu/src/Data/Random/Distribution/Normal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,22 @@ module Data.Random.Distribution.Normal
, knuthPolarNormalPair
) where

import Data.Random.Internal.Words
import Data.Bits

import Data.Random.Source
import Data.Random.Distribution
import Data.Random.Distribution.Uniform
import Data.Random.Distribution.Ziggurat
import Data.Random.RVar
import Data.Word

import Data.Vector.Generic (Vector)
import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as UV

import Data.Number.Erf

import qualified System.Random.Stateful as Random

-- |A random variable that produces a pair of independent
-- normally-distributed values.
normalPair :: (Floating a, Distribution StdUniform a) => RVar (a,a)
Expand Down Expand Up @@ -141,7 +142,7 @@ realFloatStdNormal = runZiggurat (normalZ p getIU `asTypeOf` (undefined :: Ziggu

getIU :: (Num a, Distribution Uniform a) => RVarT m (Int, a)
getIU = do
i <- getRandomWord8
i <- Random.uniformWord8 RGen
u <- uniformT (-1) 1
return (fromIntegral i .&. (2^p-1), u)

Expand All @@ -167,10 +168,24 @@ doubleStdNormalZ = mkZiggurat_ True
where
getIU :: RVarT m (Int, Double)
getIU = do
!w <- getRandomWord64
!w <- Random.uniformWord64 RGen
let (u,i) = wordToDoubleWithExcess w
return $! (fromIntegral i .&. (doubleStdNormalC-1), u+u-1)

-- NOTE: inlined from random-source
{-# INLINE wordToDouble #-}
-- |Pack the low 52 bits from a 'Word64' into a 'Double' in the range [0,1).
-- Used to convert a 'stdUniform' 'Word64' to a 'stdUniform' 'Double'.
wordToDouble :: Word64 -> Double
wordToDouble x = (encodeFloat $! toInteger (x .&. 0x000fffffffffffff {- 2^52-1 -})) $ (-52)

{-# INLINE wordToDoubleWithExcess #-}
-- |Same as wordToDouble, but also return the unused bits (as the 12
-- least significant bits of a 'Word64')
wordToDoubleWithExcess :: Word64 -> (Double, Word64)
wordToDoubleWithExcess x = (wordToDouble x, x `shiftR` 52)


-- |A random variable sampling from the standard normal distribution
-- over the 'Float' type.
floatStdNormal :: RVarT m Float
Expand All @@ -193,10 +208,24 @@ floatStdNormalZ = mkZiggurat_ True
where
getIU :: RVarT m (Int, Float)
getIU = do
!w <- getRandomWord32
!w <- Random.uniformWord32 RGen
let (u,i) = word32ToFloatWithExcess w
return (fromIntegral i .&. (floatStdNormalC-1), u+u-1)

-- NOTE: inlined from random-source
{-# INLINE word32ToFloat #-}
-- |Pack the low 23 bits from a 'Word32' into a 'Float' in the range [0,1).
-- Used to convert a 'stdUniform' 'Word32' to a 'stdUniform' 'Double'.
word32ToFloat :: Word32 -> Float
word32ToFloat x = (encodeFloat $! toInteger (x .&. 0x007fffff {- 2^23-1 -} )) $ (-23)

{-# INLINE word32ToFloatWithExcess #-}
-- |Same as word32ToFloat, but also return the unused bits (as the 9
-- least significant bits of a 'Word32')
word32ToFloatWithExcess :: Word32 -> (Float, Word32)
word32ToFloatWithExcess x = (word32ToFloat x, x `shiftR` 23)


normalCdf :: (Real a) => a -> a -> a -> Double
normalCdf m s x = normcdf ((realToFrac x - realToFrac m) / realToFrac s)

Expand Down
Loading

0 comments on commit 82d8fb1

Please sign in to comment.