packages feed

distribution (empty) → 1.0.0.0

raw patch · 10 files changed

+1406/−0 lines, 10 filesdep +MonadRandomdep +arraydep +basesetup-changed

Dependencies added: MonadRandom, array, base, containers, random

Files

+ Data/Distribution.hs view
@@ -0,0 +1,175 @@+{- Copyright 2014 Romain Edelmann++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License. -}++-- | This module defines finite discrete probability distributions+--   and efficient ways to construct, modify, combine, measure and sample them.+--+--   The various functionalities are each defined in their own submodules and+--   simply re-exported here. Note that not all modules in the package are+--   directly exported by this top-level module.+module Data.Distribution+    ( -- * Exported modules++      module Data.Distribution.Core+      -- | The "Data.Distribution.Core" module contains the definition of+      --   finite discrete probability distributions, as well as functions for+      --   constructing, deconstructing and combining such distributions.++    , module Data.Distribution.Measure+      -- | The "Data.Distribution.Measure" module contains functions to measure+      --   the 'probability' of events, the 'expectation' and 'variance' of+      --   numeric distributions as well as functions for getting interesting+      --   values, such as 'median', 'quantile's and 'modes', out of+      --   distributions.++    , module Data.Distribution.Aggregator+      -- | The "Data.Distribution.Aggregator" module provides way to modify+      --   the probabilities of lists of values tagged with their probability.+      --   The module also defines common aggregators such as 'complementary'+      --   or 'cumulative'.++    , module Data.Distribution.Sample+      -- | The "Data.Distribution.Sample" module provides ways to efficiently+      --   randomly sample values from distributions.++      -- * Other modules++      -- | Not all modules related to distributions are exported by default.+      --   Here is a list of such modules:+      --+      --       * "Data.Distribution.Plot" : For plotting distributions.+      --                                    This module is part of the+      --                                    @distribution-plot@ package.+      --+      --       * "Data.Distribution.Domain.Dice" : Distributions over dice.+      --+      --       * "Data.Distribution.Domain.Coin" : Distributions over coins.++      -- * Usage++      -- ** Basics++      -- | To illustrate how to use the module, let's walk through some simple+      --   examples. Let us first create a uniform distribution over the+      --   integers from 1 to 4.+      --+      --   >>> uniform [1 .. 4]+      --   fromList [(1,1 % 4),(2,1 % 4),(3,1 % 4),(4,1 % 4)]+      --+      --   The textual representation of distributions lists every value in the+      --   distribution with non-zero probability, in ascending order. To each+      --   value is associated its probability in the distribution.+      --+      --   We can use the 'probability' function to get the probability of some+      --   predicate in the distribution.+      --+      --   >>> probability (>= 2) $ uniform [1 .. 4]+      --   3 % 4+      --   >>> probability (< 1) $ uniform [1 .. 4]+      --   0 % 1++      -- ** Measures++      -- | We can also compute some other measures on the distributions, such+      --   as for instance 'expectation' and 'variance'.+      --   (For more details, see "Data.Distribution.Measure")+      --+      --   >>> expectation $ uniform [1 .. 4]+      --   2.5+      --   >>> variance $ uniform [1 .. 4]+      --   1.25++      -- ** Transforming distributions++      -- | Distributions can be transformed and combined in various ways.+      --   For instance, to apply a function on the values in a distribution+      --   'select' can be used.+      --   (For more details, see "Data.Distribution.Core")+      --+      --   >>> select (\ x -> x * x) $ uniform [-2, 0, 2]+      --   fromList [(0,1 % 3),(4,2 % 3)]+      --   >>> select (> 3) $ uniform [1 .. 10]+      --   fromList [(False,3 % 10),(True,7 % 10)]+      --+      --   The 'andThen' function can be used to create distributions+      --   that result from first taking a value from a distribution,+      --   and then, depending on that value, returning a new distribution.+      --+      --   >>> uniform [1 .. 2] `andThen` (\ n -> uniform [-n .. n])+      --   fromList [(-2,1 % 10),(-1,4 % 15),(0,4 % 15),(1,4 % 15),(2,1 % 10)]++      -- *** Numeric distributions++      -- | Distributions over numeric values can also be combined using+      --   addition, substraction, multiplication and division.+      --+      --   >>> uniform [1 .. 4] + uniform [1 .. 2]+      --   fromList [(2,1 % 8),(3,1 % 4),(4,1 % 4),(5,1 % 4),(6,1 % 8)]+      --   >>> uniform [1 .. 4] * uniform [0 .. 1]+      --   fromList [(0,1 % 2),(1,1 % 8),(2,1 % 8),(3,1 % 8),(4,1 % 8)]+      --+      --   For multiple experiments, the 'trials' and 'times' functions+      --   can be used. @trials@ counts the number of successes from+      --   @n@ random independant experiments.+      --+      --   >>> trials 4 $ uniform [True, False]+      --   fromList [(0,1 % 16),(1,1 % 4),(2,3 % 8),(3,1 % 4),(4,1 % 16)]+      --   >>> trials 2 $ withProbability 0.75+      --   fromList [(0,1 % 16),(1,3 % 8),(2,9 % 16)]+      --+      --   On the other hand, 'times' sums the outcome of @n@+      --   independant experiments.+      --+      --   >>> times 2 $ uniform [1, 2, 3]+      --   fromList [(2,1 % 9),(3,2 % 9),(4,1 % 3),(5,2 % 9),(6,1 % 9)]+      --+      --   Note the difference between @*@ and 'times'.+      --+      --   >>> times 2 $ uniform [1 .. 2]+      --   fromList [(2,1 % 4),(3,1 % 2),(4,1 % 4)]+      --   >>> 2 * uniform [1 .. 2]+      --   fromList [(2,1 % 2),(4,1 % 2)]++      -- ** Sampling++      -- | To get random values from distributions, we must first create+      --   a generator. For this, the 'fromDistribution' function is used.+      --   Once we have a generator, we can get random values using the+      --   'sample' or 'getSample' functions. 'sample' takes a generator+      --   and a 'StdGen' from "System.Random" and returns a random value+      --   from the distribution and a new 'StdGen'.+      --+      --   >>> let g = fromDistribution $ trials 10 $ withProbability 0.75+      --   >>> fst $ sample g $ mkStdGen 12345+      --   7+      --   >>> fst $ sample g $ mkStdGen 67890+      --   9+      --+      --   On the other hand, 'getSample' does the same, but directly in a+      --   'MonadRandom' from "Control.Monad.Random".+      --   (See "Data.Distribution.Sample" for more details)++      -- ** Plotting++      -- | Have a look at the "Data.Distribution.Plot" module made available+      --   by the @distribution-plot@ package if you are interested+      --   in plotting distributions to files.+    ) where++import System.Random (mkStdGen)  -- For doctest.++import Data.Distribution.Core+import Data.Distribution.Measure+import Data.Distribution.Aggregator+import Data.Distribution.Sample
+ Data/Distribution/Aggregator.hs view
@@ -0,0 +1,107 @@+{- Copyright 2014 Romain Edelmann++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License. -}+++-- | Module containing functions to apply on+--   lists of values tagged with their probability,+--   in order to somehow aggregate or transform the+--   probabilities.+module Data.Distribution.Aggregator+    ( -- * Aggregation+      Aggregator+      -- ** Creation+    , makeAggregator+    , makePureAggregator+    , separated+      -- ** Application+    , modifyProbabilities+    , aggregateWith+      -- ** Useful aggregators+    , cumulative+    , decreasing+    , complementary+    ) where++import Data.Monoid++import Data.Distribution.Core+++-- Aggregation+++-- | Functions that can modify probabilities.+newtype Aggregator a = Aggregator+    { modifyProbabilities :: [(a, Probability)] -> [Probability]+      -- ^ Applies the aggregator and returns the modified list+      --   of probabilities.+    }++-- | 'mempty' is the aggregator that leaves probabilities untouched,+--   and 'mappend' compose aggregators.+instance Monoid (Aggregator a) where+    mempty = Aggregator (map snd)+    mappend (Aggregator f) g = Aggregator (f . aggregateWith g)++-- | Applies an aggregator on a list of values tagged with their probability.+--   The values themselves are left unchanged.+aggregateWith :: Aggregator a -> [(a, Probability)] -> [(a, Probability)]+aggregateWith (Aggregator f) xs = zip vs $ f xs+  where+    vs = map fst xs++-- | Creates an aggregator from a function ignoring the values.+--   The function should not modify the number of elements.+makePureAggregator :: ([Probability] -> [Probability]) -> Aggregator a+makePureAggregator f = Aggregator $ f . map snd++-- | Creates an aggregator from a function.+--   The function should not modify the number of elements.+makeAggregator :: ([(a, Probability)] -> [Probability]) -> Aggregator a+makeAggregator = Aggregator++-- | Aggregator that applies the first aggregator on values less than @x@+--   and the second on values greater than @x@. Potential probability at @x@+--   is left untouched.+separated :: Ord a => a -> Aggregator a -> Aggregator a -> Aggregator a+separated x la ga = makeAggregator go+  where+    go xs = mconcat+        [ modifyProbabilities la ls+        , modifyProbabilities mempty es+        , modifyProbabilities ga gs ]+      where+        (ls, egs) = span ((< x) . fst) xs+        (es, gs) = span ((== x) . fst) egs++-- | Adds to each probability the sum of the probabilities earlier in the list.+--+--   >>> aggregateWith cumulative $ toList $ uniform [1 .. 5]+--   [(1,1 % 5),(2,2 % 5),(3,3 % 5),(4,4 % 5),(5,1 % 1)]+cumulative :: Aggregator a+cumulative = makePureAggregator (scanl1 (+))++-- | Replaces each probability by its complement.+--+--   >>> aggregateWith complementary $ toList $ uniform [1 .. 5]+--   [(1,4 % 5),(2,4 % 5),(3,4 % 5),(4,4 % 5),(5,4 % 5)]+complementary :: Aggregator a+complementary = makePureAggregator (map (1 -))++-- | Adds to each probability the sum of probabilities later in the list.+--+--   >>> aggregateWith decreasing  $ toList $ uniform [1 .. 5]+--   [(1,1 % 1),(2,4 % 5),(3,3 % 5),(4,2 % 5),(5,1 % 5)]+decreasing :: Aggregator a+decreasing = makePureAggregator (scanr1 (+))
+ Data/Distribution/Core.hs view
@@ -0,0 +1,388 @@+{-# LANGUAGE MultiWayIf #-}++{- Copyright 2014 Romain Edelmann++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License. -}+++-- | This modules defines types and functions for manipulating+--   finite discrete probability distributions.+module Data.Distribution.Core+    ( -- * Probability+      Probability+      -- * Distribution+    , Distribution+    , toMap+    , toList+      -- ** Properties+    , size+    , support+      -- ** Creation+    , fromList+    , always+    , uniform+    , withProbability+      -- ** Transformation+    , select+    , assuming+      -- ** Combination+    , combine+      -- ** Sequences+      -- *** Independant experiments+    , trials+    , times+      -- *** Dependant experiments+    , andThen+    , on+    ) where++import Control.Arrow (second)+import qualified Data.Function as F+import Data.List (tails, groupBy, sortBy, find)+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Maybe (fromMaybe)+import Data.Monoid+import Data.Ord (comparing)+import Data.Set (Set)+++-- | Probability. Should be between 0 and 1.+type Probability = Rational++-- | Distribution over values of type @a@.+--+--   Due to their internal representations, @Distribution@ can not have+--   @Functor@ or @Monad@ instances.+--   However, 'select' is the equivalent of @fmap@ for distributions+--   and 'always' and 'andThen' are respectively the equivalent of @return@+--   and @>>=@.+newtype Distribution a = Distribution+    { toMap :: Map a Probability+      -- ^ Converts the distribution to a mapping from values to their+      --   probability. Values with probability @0@ are not included+      --   in the resulting mapping.+    } deriving Eq++instance Show a => Show (Distribution a) where+    show d = "fromList " ++ show (toList d)++-- | A distribution @d1@ is less than some other distribution @d2@+--   if the smallest value that has a different probability+--   in @d1@ and @d2@ is more probable in @d1@.+--+--   By convention, empty distributions are less than+--   everything except themselves.+instance Ord a => Ord (Distribution a) where+    compare d1 d2 = case (toList d1, toList d2) of+        ([], []) -> EQ+        ([], _)  -> LT+        (_, [])  -> GT+        (xs, ys) -> case find (uncurry (/=)) $ zip xs ys of+            Nothing -> EQ+            Just ((x, p), (y, q)) -> case compare x y of+                EQ -> compare q p+                c  -> c++-- | Lifts the bounds to the distributions that return them+--   with probability one.+--+--   Note that the degenerate distributions of size @0@ will+--   be less than the distribution @minBound@.+--+--   Appart from that, all other distributions d have+--   the property that @minBound <= d <= maxBound@ if+--   this property holds on the values of the distribution.+instance Bounded a => Bounded (Distribution a) where+    minBound = always minBound+    maxBound = always maxBound++-- | Literals are interpreted as distributions that always+--   return the given value.+--+--   >>> 42 == always 42+--   True+--+--   Binary operations on distributions are defined to+--   be the binary operation on each pair of elements.+--+--   For this reason, @(+)@ and @(*)@ are not related in the same way+--   as they are on natural numbers.+--+--   For instance, it is not always the case that:+--   @3 * d == d + d + d@+--+--   >>> let d = uniform [0, 1]+--   >>> 3 * d+--   fromList [(0,1 % 2),(3,1 % 2)]+--   >>> d + d + d+--   fromList [(0,1 % 8),(1,3 % 8),(2,3 % 8),(3,1 % 8)]+--+--   For this particular behavior, see the `times` function.+instance (Ord a, Num a) => Num (Distribution a) where+    fromInteger = always . fromInteger+    abs = select abs+    signum = select signum+    negate = select negate+    d1 + d2 = d1 `andThen` (+) `on` d2+    d1 - d2 = d1 `andThen` (-) `on` d2+    d1 * d2 = d1 `andThen` (*) `on` d2++-- Binary operations on distributions are defined to+-- be the binary operation on each pair of elements.+instance (Ord a, Fractional a) => Fractional (Distribution a) where+    fromRational = always . fromRational+    d1 / d2 = d1 `andThen` (/) `on` d2+    recip = select recip++-- Binary operations on distributions are defined to+-- be the binary operation on each pair of element.+instance (Ord a, Floating a) => Floating (Distribution a) where+    pi = always pi+    exp = select exp+    sqrt = select sqrt+    log = select log+    d1 ** d2 = d1 `andThen` (**) `on` d2+    d1 `logBase` d2 = d1 `andThen` logBase `on` d2+    sin = select sin+    tan = select tan+    cos = select cos+    asin = select asin+    atan = select atan+    acos = select acos+    sinh = select sinh+    tanh = select tanh+    cosh = select cosh+    asinh = select asinh+    atanh = select atanh+    acosh = select acosh++instance (Ord a, Monoid a) => Monoid (Distribution a) where+    mempty = always mempty+    mappend d1 d2 = d1 `andThen` mappend `on` d2++-- | Converts the distribution to a list of increasing values whose probability+--   is greater than @0@. To each value is associated its probability.+toList :: Distribution a -> [(a, Probability)]+toList (Distribution xs) = Map.toAscList xs+++-- Properties+++-- | Returns the number of elements with non-zero probability+--   in the distribution.+size :: Distribution a -> Int+size = Map.size . toMap++-- | Values in the distribution with non-zero probability.+support :: Distribution a -> Set a+support = Map.keysSet . toMap+++-- Creation+++-- | Distribution that assigns to each @value@ from the given @(value, weight)@+--   pairs a probability proportional to @weight@.+--+--   >>> fromList [('A', 1), ('B', 2), ('C', 1)]+--   fromList [('A',1 % 4),('B',1 % 2),('C',1 % 4)]+--+--   Values may appear multiple times in the list. In this case, their total+--   weight is the sum of the different associated weights.+--   Values whose total weight is zero or negative are ignored.+fromList :: (Ord a, Real p) => [(a, p)] -> Distribution a+fromList xs = Distribution $ Map.fromDistinctAscList $ zip vs scaledPs+  where+    as = map aggregate $ groupBy ((==) `F.on` fst) $ sortBy (comparing fst) xs+      where+        aggregate ys = let (v : _, qs) = unzip ys in+            (v, fromRational $ toRational $ sum qs)+    (vs, ps) = unzip $ filter ((> 0) . snd) as+    t = sum ps+    scaledPs = if t /= 1 then map (/ t) ps else ps++-- | Distribution that assigns to @x@ the probability of @1@.+--+-- >>> always 0+-- fromList [(0,1 % 1)]+--+-- >>> always 42+-- fromList [(42,1 % 1)]+always :: a -> Distribution a+always x = Distribution $ Map.singleton x 1++-- | Uniform distribution over the values.+--   The probability of each element is proportional+--   to its number of appearance in the list.+--+--   >>> uniform [1 .. 6]+--   fromList [(1,1 % 6),(2,1 % 6),(3,1 % 6),(4,1 % 6),(5,1 % 6),(6,1 % 6)]+uniform :: (Ord a) => [a] -> Distribution a+uniform xs = fromList $ fmap (\ x -> (x, p)) xs+  where+    p = 1 / toRational (length xs)++-- | @True@ with given probability and @False@ with complementary probability.+withProbability :: Real p => p -> Distribution Bool+withProbability p = fromList [(False, 1 - p'), (True, p')]+  where+    p' = fromRational $ max 0 $ min 1 $ toRational p+++-- Transformation+++-- | Applies a function to the values in the distribution.+--+--   >>> select abs $ uniform [-1, 0, 1]+--   fromList [(0,1 % 3),(1,2 % 3)]+select :: Ord b => (a -> b) -> Distribution a -> Distribution b+select f (Distribution xs) = Distribution $ Map.mapKeysWith (+) f xs++-- | Returns a new distribution conditioning on the predicate holding+--   on the value.+--+--   >>> assuming (> 2) $ uniform [1 .. 6]+--   fromList [(3,1 % 4),(4,1 % 4),(5,1 % 4),(6,1 % 4)]+--+--   Note that the resulting distribution will be empty+--   if the predicate does not hold on any of the values.+--+--   >>> assuming (> 7) $ uniform [1 .. 6]+--   fromList []+assuming :: (a -> Bool) -> Distribution a -> Distribution a+assuming f (Distribution xs) = Distribution $ fmap adjust filtered+  where+    filtered = Map.filterWithKey (const . f) xs+    adjust x = x * (1 / total)+    total = sum $ Map.elems filtered+++-- Combination+++-- | Combines multiple weighted distributions into a single distribution.+--+--   The probability of each element is the weighted sum of the element's+--   probability in every distribution.+--+--   >>> combine [(always 2, 1 / 3), (uniform [1..6], 2 / 3)]+--   fromList [(1,1 % 9),(2,4 % 9),(3,1 % 9),(4,1 % 9),(5,1 % 9),(6,1 % 9)]+--+--   Note that the weights do not have to sum up to @1@. Distributions with+--   negative or null weight will be ignored.+combine :: (Ord a, Real p) => [(Distribution a, p)] -> Distribution a+combine dws = Distribution $ Map.unionsWith (+) $ zipWith go ds ps+  where+    (ds, ws) = unzip $ filter ((> 0) . snd) $ map (second toRational) dws+    w = sum ws+    ps = map (/ w) ws+    go (Distribution xs) p = fmap (* p) xs+++-- Sequences+++-- | Binomial distribution.+--   Assigns to each number of successes its probability.+--+--   >>> trials 2 $ uniform [True, False]+--   fromList [(0,1 % 4),(1,1 % 2),(2,1 % 4)]+trials :: Int -> Distribution Bool -> Distribution Int+trials n d = Distribution $ Map.fromDistinctAscList $ if+    | p == 1    -> [(n, 1)]+    | p == 0    -> [(0, 1)]+    | otherwise -> zip outcomes probs+  where+    p = fromMaybe 0 $ Map.lookup True $ toMap d+    q = 1 - p++    ps = take (n + 1) $ iterate (* p) 1+    qs = reverse $ take (n + 1) $ iterate (* q) 1++    probs = zipWith (*) pascalRow $ zipWith (*) ps qs++    outcomes = [0 .. n]++    pascalRow = fmap (fromRational . toRational) $+        scanl ( \ c k -> c * (n' + 1 - k) `div` k) 1 [1 .. n']+      where+        n' = toInteger n++-- | Takes `n` samples from the distribution and returns the distribution+--   of their sum.+--+--   >>> times 2 $ uniform [1 .. 3]+--   fromList [(2,1 % 9),(3,2 % 9),(4,1 % 3),(5,2 % 9),(6,1 % 9)]+--+--   This function makes use of the more efficient @trials@ functions+--   for input distributions of size @2@.+--+--   >>> size $ times 10000 $ uniform [1, 10]+--   10001+times :: (Num a, Ord a) => Int -> Distribution a -> Distribution a+n `times` d+    | s == 0 = d+    | n <= 0 = always 0+    | s == 1 = select (* n') d+    | s == 2 = case toList d of  -- Performs Bernoulli trials. (efficiency)+        [(a, p), (b, q)] -> select (go a b) $ trials n $ withProbability p+        _ -> error "times: size seems not to be properly defined."+    | otherwise = mult n+  where+    s = Map.size $ toMap d+    n' = fromInteger $ toInteger n+    go a b k = k' * a + (n' - k') * b+      where+        k' = fromInteger $ toInteger k++    -- Computes @k `times` d@ using a divide and conquer approach.+    mult 1 = d+    mult k = if r == 0 then twice d' else twice d' + d+      where+        d' = mult k'+        (k', r) = k `quotRem` 2++    -- Computes @d + d@ more efficiently.+    twice (Distribution xs) = Distribution $ Map.unionsWith (+) $ do+        (x, p) : ys <- init $ tails $ Map.toAscList xs+        return $ Map.fromDistinctAscList $ (:) (x + x, p * p) $ do+            (y, q) <- ys+            let p' = 2 * p * q+            return (y + x, p')++-- | Computes for each value in the distribution a new distribution, and then+--   combines those distributions, giving each the weight of the original value.+--+--   >>> uniform [1 .. 3] `andThen` (\ n -> uniform [1 .. n])+--   fromList [(1,11 % 18),(2,5 % 18),(3,1 % 9)]+--+--   See the 'on' function for a convenient way to chain distributions.+infixl 7 `andThen`+andThen :: Ord b => Distribution a -> (a -> Distribution b) -> Distribution b+andThen (Distribution xs) f = Distribution $+    Map.unionsWith (+) $ fmap go $ Map.toList xs+  where+    go (x, p) = fmap (* p) $ toMap $ f x++-- | Utility to partially apply a function on a distribution.+--   A use case for 'on' is to use it in conjunction with 'andThen'+--   to combine distributions.+--+--   >>> uniform [1 .. 3] `andThen` (+) `on` uniform [1 .. 2]+--   fromList [(2,1 % 6),(3,1 % 3),(4,1 % 3),(5,1 % 6)]+infixl 8 `on`+on :: Ord c => (a -> b -> c) -> Distribution b -> a -> Distribution c+on f d x = select (f x) d
+ Data/Distribution/Domain/Coin.hs view
@@ -0,0 +1,46 @@+{- Copyright 2014 Romain Edelmann++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License. -}++-- | This modules provides distributions from coins and+--   functions on coins.+module Data.Distribution.Domain.Coin+    ( -- * Coin+      Coin+    , CoinSide (..)+    , coin+      -- ** Operations+    , flipsOf+    , reflipOn+    ) where++import Data.Distribution.Core++-- | Distribution over the sides of a coin.+type Coin = Distribution CoinSide++-- | Possible outcomes of a coin flip.+data CoinSide = Head | Tail+  deriving (Eq, Ord, Show, Read, Enum)++-- | Fair coin.+coin :: Coin+coin = uniform [Head, Tail]++-- | Flips `n` times the given coin and counts the number of heads.+flipsOf :: Int -> Coin -> Distribution Int+n `flipsOf` d = n `trials` select (== Head) d++-- | Rerolls the coin once if the first outcome satifies the given predicate.+reflipOn :: CoinSide -> Coin -> Coin+reflipOn s d = d `andThen` \ r -> if r == s then d else always r
+ Data/Distribution/Domain/Dice.hs view
@@ -0,0 +1,72 @@+{- Copyright 2014 Romain Edelmann++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License. -}+++-- | This modules provides distributions from dice and+--   functions on dice.+module Data.Distribution.Domain.Dice+    ( -- * Dice+      Dice+    , dice+      -- ** Common dice+    , d4+    , d6+    , d8+    , d10+    , d20+      -- ** Operations+    , rollsOf+    , rerollOn+    ) where++import Data.Distribution.Core++-- | Distribution of the result of dice rolls.+type Dice = Distribution Int++-- | Fair dice of @n@ faces.+dice :: Int -> Dice+dice n = uniform [1 .. n]++-- | Fair dice of @4@ faces.+d4 :: Dice+d4 = dice 4++-- | Fair dice of @6@ faces.+d6 :: Dice+d6 = dice 6++-- | Fair dice of @8@ faces.+d8 :: Dice+d8 = dice 8++-- | Fair dice of @10@ faces.+d10 :: Dice+d10 = dice 10++-- | Fair dice of @12@ faces.+d12 :: Dice+d12 = dice 12++-- | Fair dice of @20@ faces.+d20 :: Dice+d20 = dice 20++-- | Rolls `n` times the given dice and sums the results.+rollsOf :: Int -> Dice -> Dice+n `rollsOf` d = n `times` d++-- | Rerolls the dice once if the first outcome satifies the given predicate.+rerollOn :: (Int -> Bool) -> Dice -> Dice+rerollOn f d = d `andThen` \ n -> if f n then d else always n
+ Data/Distribution/Measure.hs view
@@ -0,0 +1,153 @@+{- Copyright 2014 Romain Edelmann++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License. -}+++-- | This modules provides various measures on+--   finite discrete probability distributions.+module Data.Distribution.Measure+    ( -- * Probability+      probability+    , probabilityAt+    , probabilityIn+      -- * Expectation+    , expectation+    , mean+      -- * Variation+    , variance+    , standardDeviation+      -- * Values+    , median+    , modes+    , quantile+    ) where++import Control.Arrow (second)+import qualified Data.Map as Map+import Data.Maybe (fromMaybe)++import Data.Distribution.Core+++-- | Probability that a predicate holds on the distribution.+--+--   >>> probability (\ x -> x == 1 || x == 6) $ uniform [1 .. 6]+--   1 % 3+--+--   Takes @O(n)@ time. See 'probabilityAt' and 'probabilityIn'+--   for a more efficient ways to query elements and ranges.+probability :: (a -> Bool) -> Distribution a -> Probability+probability f = sum . Map.elems . Map.filterWithKey (const . f) . toMap++-- | Probability of a given value.+--+--   Takes @O(log(n))@ time.+probabilityAt :: Ord a => a -> Distribution a -> Probability+probabilityAt x = fromMaybe 0 . Map.lookup x . toMap++-- | Probability of a the inclusive @[low, high]@ range.+--   When @low > high@, the probability is 0.+--+--   Takes @O(log(n) + m)@ time, where @n@ is the size of+--   the distribution and @m@ the size of the range.+probabilityIn :: Ord a => (a, a) -> Distribution a -> Probability+probabilityIn (low, high) d+    | low > high = 0+    | low == high = probabilityAt low d+    | otherwise = Map.foldl' (+) (ph + pl) ps+  where+    (_, ml, hs) = Map.splitLookup low $ toMap d+    (ps, mh, _) = Map.splitLookup high hs++    pl = fromMaybe 0 ml+    ph = fromMaybe 0 mh++-- | Returns the expectation, or mean, of a distribution.+--+-- >>> expectation $ uniform [0, 1]+-- 0.5+--+-- Empty distributions have an expectation of @0@.+expectation :: (Real a, Fractional b) => Distribution a -> b+expectation = fromRational . sum .+    fmap (uncurry (*) . second toRational) .+    Map.toList . Map.mapKeysWith (+) toRational . toMap++-- | Returns the variance of a distribution.+--+-- >>> variance $ always 1+-- 0.0+-- >>> variance $ uniform [0 .. 1]+-- 0.25+-- >>> variance $ uniform [1 .. 7]+-- 4.0+--+-- Empty distributions have a variance of @0@.+variance :: (Real a, Fractional b) => Distribution a -> b+variance d = expectation dSquare - (e * e)+  where+    e = expectation d+    dSquare = select (square . toRational) d+    square x = x * x++-- | Standard deviation.+--+--   >>> standardDeviation $ always 1+--   0.0+--   >>> standardDeviation $ uniform [0 .. 1]+--   0.5+--   >>> standardDeviation $ uniform [1 .. 7]+--   2.0+standardDeviation :: (Real a, Floating b) => Distribution a -> b+standardDeviation = sqrt . fromRational . variance++-- | Returns the smallest value in the distribution such that+--   at least a fraction `p` of the values are less or equal to it.+--+--   >>> quantile 0.0 $ uniform [1, 2, 3]+--   Just 1+--   >>> quantile 0.5 $ uniform [1, 2, 3]+--   Just 2+--   >>> quantile 1.0 $ uniform [1, 2, 3]+--   Just 3+--   >>> quantile 0.5 $ fromList []+--   Nothing+quantile :: Probability -> Distribution a -> Maybe a+quantile p d = case dropWhile ((< r) . snd) $ scanl1 go $ toList d of+    (x, _) : _ -> Just x+    _          -> Nothing+  where+    r = max 0 $ min 1 p+    go (_, q') (x, q) = (x, q' + q)++-- | Returns the median of the values.+--   The median is the smallest value such that at least 50% of+--   the values are less or equal to it.+--+--   >>> median $ fromList [(1, 0.6), (2, 0.4)]+--   Just 1+--   >>> median $ fromList [(1, 0.4), (2, 0.6)]+--   Just 2+median :: Distribution a -> Maybe a+median = quantile 0.5++-- | Synonym of 'expectation'.+mean :: (Real a, Fractional b) => Distribution a -> b+mean = expectation++-- | Returns all values whose probability is maximal.+modes :: Distribution a -> [a]+modes d = map fst $ filter ((m ==) . snd) xs+  where+    xs = toList d+    m = maximum $ map snd xs
+ Data/Distribution/Sample.hs view
@@ -0,0 +1,196 @@+{-# LANGUAGE MultiWayIf #-}++{- Copyright 2014 Romain Edelmann++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License. -}+++-- | This modules provides ways to randomly and efficiently sample values+--   from distributions.+--+--   Walker's <http://en.wikipedia.org/wiki/Alias_method alias method> is+--   used internally, so that values can be sampled in constant time.+module Data.Distribution.Sample+    ( -- * Generator+      Generator+      -- ** Building+    , fromDistribution+    , safeFromDistribution+      -- ** Sampling+    , sample+    , getSample+    ) where++import Control.Monad.Random.Class (MonadRandom, getRandom, getRandomR)+import Control.Monad.ST.Safe+import Data.Array.IArray+import Data.Array.MArray.Safe+import Data.Array.Unboxed+import Data.Array.ST.Safe+import System.Random (RandomGen, random, randomR)++import Data.Distribution.Core++-- | Generator of random values of type @a@.+--+--   Can be created in linear time from distributions+--   and sampled in constant time.+data Generator a = Generator+    { capacity :: !Int+      -- ^ Number of buckets.+    , probabilities :: !(UArray Int Double)+      -- ^ Probability to stay in the bucket.+    , values :: !(Array Int a)+      -- ^ Value in the bucket.+    , indexes :: !(UArray Int Int)+      -- ^ Index of the "guest" value. Used when the bucket is left.+    }++instance Functor Generator where+    fmap f (Generator n ps vs is) = Generator n ps (fmap f vs) is++-- | Creates a generator from the given non-empty distribution.+--+--   Runs in @O(n)@ time where @n@ is the size of the distribution.+fromDistribution :: Distribution a -> Generator a+fromDistribution d = case toList d of+    [] -> error "makeGenerator: Undefined on empty distributions."+    xs -> generate xs+  where+    n = size d++    -- Creates the generator using Walker's algorithm.+    --+    -- The main idea is to put each value into its own bucket.+    -- In addition, each bucket has a probability to be discarded when picked,+    -- in which case another value, the "guest" of the bucket,+    -- is chosen instead.+    --+    -- The following procedure sets the probabilities and guests of+    -- the bucket so that the probability to choose the value of a bucket+    -- is the probability of the value in the input distribution.+    generate xs = runST $ do+        -- The values are directly from the list.+        let vs = listArray (0, n - 1) as++        -- The probability to stay in the bucket is @n@ times the+        -- probability in the distribution. This is due to the fact+        -- that each of the @n@ buckets is chosen with probability @1 / n@.+        -- Note that this can well exceed @1@. This will be taken care+        -- during the equilibration phase.+        -- In case the value exceed @1@, the bucket is said to be overfilled,+        -- and if its is strictly less than @1@, underfilled.+        ps <- stArrayFromList sqs++        -- The indexes of "guest" values.+        -- The correct indexes will be set during the equilibration phase.+        -- Guest values are used by underfilled buckets.+        is <- stuArray 0++        -- The 'go' function is used to equilibrate the buckets, by assigning+        -- unused space in underfilled buckets to overfilled buckets.+        --+        -- As first argument are the indexes which have a probability > 1+        -- (indexes of overfilled buckets),+        -- and as second argument those which have a probability < 1+        -- (indexed of underfilled buckets)+        --+        -- The idea behind the function is to take an overfilled and an+        -- underfilled bucket, and to completely "fill" the underfilled bucket.+        -- To do so, the overfilled bucket is registered as the guest of the+        -- underfilled bucket. The probability of the overfilled bucket is+        -- then reduced by the amount that was "poured" into the underfilled+        -- bucket.+        let go (o : os) (u : us) = do+                -- First, we register o as the guest of u.+                writeArray is u o++                -- We then update the probability of o.+                po <- readArray ps o+                pu <- readArray ps u+                let po' = po - (1 - pu)+                writeArray ps o po'++                -- We recurse on the new overfilled and underfilled buckets.+                if | po' < 1 -> go os (o : us)  -- We took too much from o.+                   | po' == 1 -> go os us       -- o perfectly fits its bucket.+                   | otherwise -> go (o : os) us  -- o is still too large.++            go [] [] = return ()  -- All buckets are filled.+            go _ _ = error "makeGenerator: Implementation error."++        -- We select the initial overfilled and underfilled buckets.+        let os = map fst $ filter ((> 1) . snd) iqs+            us = map fst $ filter ((< 1) . snd) iqs++        -- We perform the equilibration phase.+        go os us++        -- Each bucket is now completely filled. We freeze the result.+        fps <- freeze ps+        fis <- freeze is+        return $ Generator+            n+            (listArray (0, n - 1)+                (fmap fromRational $ elems (fps :: Array Int Rational)))+            vs+            fis+      where+        -- Separating the values from their probability.+        (as, qs) = unzip xs++        -- Scaling the probabilities by @n@. This is due to the fact that each+        -- of the @n@ buckets is uniformly chosen with probability @1 / n@.+        sqs = map (* fromIntegral n) qs++        -- Indexed and scaled probabilities.+        iqs = zip [0 ..] sqs++    stArrayFromList :: [e] -> ST s (STArray s Int e)+    stArrayFromList = newListArray (0, n - 1)++    stuArray :: e -> ST s (STArray s Int e)+    stuArray = newArray (0, n - 1)++-- | Safe version of 'fromDistribution'. Returns @Nothing@ when the+--   given distribution is empty.+safeFromDistribution :: Distribution a -> Maybe (Generator a)+safeFromDistribution d = if size d == 0+    then Nothing+    else Just $ fromDistribution d++-- | Picks a random value from the generator.+--+--   Runs in constant @O(1)@ time.+getSample :: MonadRandom m => Generator a -> m a+getSample g = do+    let n = capacity g+    u <- getRandom+    j <- getRandomR (0, n - 1)+    let i = if u < probabilities g ! j+                then j+                else indexes g ! j+    return $ values g ! i++-- | Picks a random value from the generator.+--+--   Runs in constant @O(1)@ time.+sample :: RandomGen g => Generator a -> g -> (a, g)+sample g k = (values g ! i, k'')+  where+    n = capacity g+    (j, k') = randomR (0, n - 1) k+    (u, k'') = random k'+    i = if u < probabilities g ! j+            then j+            else indexes g ! j
+ LICENSE view
@@ -0,0 +1,202 @@++                                 Apache License+                           Version 2.0, January 2004+                        http://www.apache.org/licenses/++   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++   1. Definitions.++      "License" shall mean the terms and conditions for use, reproduction,+      and distribution as defined by Sections 1 through 9 of this document.++      "Licensor" shall mean the copyright owner or entity authorized by+      the copyright owner that is granting the License.++      "Legal Entity" shall mean the union of the acting entity and all+      other entities that control, are controlled by, or are under common+      control with that entity. For the purposes of this definition,+      "control" means (i) the power, direct or indirect, to cause the+      direction or management of such entity, whether by contract or+      otherwise, or (ii) ownership of fifty percent (50%) or more of the+      outstanding shares, or (iii) beneficial ownership of such entity.++      "You" (or "Your") shall mean an individual or Legal Entity+      exercising permissions granted by this License.++      "Source" form shall mean the preferred form for making modifications,+      including but not limited to software source code, documentation+      source, and configuration files.++      "Object" form shall mean any form resulting from mechanical+      transformation or translation of a Source form, including but+      not limited to compiled object code, generated documentation,+      and conversions to other media types.++      "Work" shall mean the work of authorship, whether in Source or+      Object form, made available under the License, as indicated by a+      copyright notice that is included in or attached to the work+      (an example is provided in the Appendix below).++      "Derivative Works" shall mean any work, whether in Source or Object+      form, that is based on (or derived from) the Work and for which the+      editorial revisions, annotations, elaborations, or other modifications+      represent, as a whole, an original work of authorship. For the purposes+      of this License, Derivative Works shall not include works that remain+      separable from, or merely link (or bind by name) to the interfaces of,+      the Work and Derivative Works thereof.++      "Contribution" shall mean any work of authorship, including+      the original version of the Work and any modifications or additions+      to that Work or Derivative Works thereof, that is intentionally+      submitted to Licensor for inclusion in the Work by the copyright owner+      or by an individual or Legal Entity authorized to submit on behalf of+      the copyright owner. For the purposes of this definition, "submitted"+      means any form of electronic, verbal, or written communication sent+      to the Licensor or its representatives, including but not limited to+      communication on electronic mailing lists, source code control systems,+      and issue tracking systems that are managed by, or on behalf of, the+      Licensor for the purpose of discussing and improving the Work, but+      excluding communication that is conspicuously marked or otherwise+      designated in writing by the copyright owner as "Not a Contribution."++      "Contributor" shall mean Licensor and any individual or Legal Entity+      on behalf of whom a Contribution has been received by Licensor and+      subsequently incorporated within the Work.++   2. Grant of Copyright License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      copyright license to reproduce, prepare Derivative Works of,+      publicly display, publicly perform, sublicense, and distribute the+      Work and such Derivative Works in Source or Object form.++   3. Grant of Patent License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      (except as stated in this section) patent license to make, have made,+      use, offer to sell, sell, import, and otherwise transfer the Work,+      where such license applies only to those patent claims licensable+      by such Contributor that are necessarily infringed by their+      Contribution(s) alone or by combination of their Contribution(s)+      with the Work to which such Contribution(s) was submitted. If You+      institute patent litigation against any entity (including a+      cross-claim or counterclaim in a lawsuit) alleging that the Work+      or a Contribution incorporated within the Work constitutes direct+      or contributory patent infringement, then any patent licenses+      granted to You under this License for that Work shall terminate+      as of the date such litigation is filed.++   4. Redistribution. You may reproduce and distribute copies of the+      Work or Derivative Works thereof in any medium, with or without+      modifications, and in Source or Object form, provided that You+      meet the following conditions:++      (a) You must give any other recipients of the Work or+          Derivative Works a copy of this License; and++      (b) You must cause any modified files to carry prominent notices+          stating that You changed the files; and++      (c) You must retain, in the Source form of any Derivative Works+          that You distribute, all copyright, patent, trademark, and+          attribution notices from the Source form of the Work,+          excluding those notices that do not pertain to any part of+          the Derivative Works; and++      (d) If the Work includes a "NOTICE" text file as part of its+          distribution, then any Derivative Works that You distribute must+          include a readable copy of the attribution notices contained+          within such NOTICE file, excluding those notices that do not+          pertain to any part of the Derivative Works, in at least one+          of the following places: within a NOTICE text file distributed+          as part of the Derivative Works; within the Source form or+          documentation, if provided along with the Derivative Works; or,+          within a display generated by the Derivative Works, if and+          wherever such third-party notices normally appear. The contents+          of the NOTICE file are for informational purposes only and+          do not modify the License. You may add Your own attribution+          notices within Derivative Works that You distribute, alongside+          or as an addendum to the NOTICE text from the Work, provided+          that such additional attribution notices cannot be construed+          as modifying the License.++      You may add Your own copyright statement to Your modifications and+      may provide additional or different license terms and conditions+      for use, reproduction, or distribution of Your modifications, or+      for any such Derivative Works as a whole, provided Your use,+      reproduction, and distribution of the Work otherwise complies with+      the conditions stated in this License.++   5. Submission of Contributions. Unless You explicitly state otherwise,+      any Contribution intentionally submitted for inclusion in the Work+      by You to the Licensor shall be under the terms and conditions of+      this License, without any additional terms or conditions.+      Notwithstanding the above, nothing herein shall supersede or modify+      the terms of any separate license agreement you may have executed+      with Licensor regarding such Contributions.++   6. Trademarks. This License does not grant permission to use the trade+      names, trademarks, service marks, or product names of the Licensor,+      except as required for reasonable and customary use in describing the+      origin of the Work and reproducing the content of the NOTICE file.++   7. Disclaimer of Warranty. Unless required by applicable law or+      agreed to in writing, Licensor provides the Work (and each+      Contributor provides its Contributions) on an "AS IS" BASIS,+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+      implied, including, without limitation, any warranties or conditions+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+      PARTICULAR PURPOSE. You are solely responsible for determining the+      appropriateness of using or redistributing the Work and assume any+      risks associated with Your exercise of permissions under this License.++   8. Limitation of Liability. In no event and under no legal theory,+      whether in tort (including negligence), contract, or otherwise,+      unless required by applicable law (such as deliberate and grossly+      negligent acts) or agreed to in writing, shall any Contributor be+      liable to You for damages, including any direct, indirect, special,+      incidental, or consequential damages of any character arising as a+      result of this License or out of the use or inability to use the+      Work (including but not limited to damages for loss of goodwill,+      work stoppage, computer failure or malfunction, or any and all+      other commercial damages or losses), even if such Contributor+      has been advised of the possibility of such damages.++   9. Accepting Warranty or Additional Liability. While redistributing+      the Work or Derivative Works thereof, You may choose to offer,+      and charge a fee for, acceptance of support, warranty, indemnity,+      or other liability obligations and/or rights consistent with this+      License. However, in accepting such obligations, You may act only+      on Your own behalf and on Your sole responsibility, not on behalf+      of any other Contributor, and only if You agree to indemnify,+      defend, and hold each Contributor harmless for any liability+      incurred by, or claims asserted against, such Contributor by reason+      of your accepting any such warranty or additional liability.++   END OF TERMS AND CONDITIONS++   APPENDIX: How to apply the Apache License to your work.++      To apply the Apache License to your work, attach the following+      boilerplate notice, with the fields enclosed by brackets "[]"+      replaced with your own identifying information. (Don't include+      the brackets!)  The text should be enclosed in the appropriate+      comment syntax for the file format. We also recommend that a+      file or class name and description of purpose be included on the+      same "printed page" as the copyright notice for easier+      identification within third-party archives.++   Copyright [yyyy] [name of copyright owner]++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ distribution.cabal view
@@ -0,0 +1,65 @@++-- The name of the package.+name:                distribution++-- The package version.  See the Haskell package versioning policy (PVP)+-- for standards guiding when and how versions should be incremented.+-- http://www.haskell.org/haskellwiki/Package_versioning_policy+-- PVP summary:      +-+------- breaking API changes+--                   | | +----- non-breaking API additions+--                   | | | +--- code changes with no API change+version:             1.0.0.0++-- A short (one-line) description of the package.+synopsis:             Finite discrete probability distributions.++-- A longer description of the package.+description:          Package for manipulating finite discrete probability distributions. Supports transformations, measurements, efficient sampling and plotting.++-- URL for the project homepage or repository.+homepage:            https://github.com/redelmann/haskell-distribution++-- The license under which the package is released.+license:             Apache-2.0++-- The file containing the license text.+license-file:        LICENSE++-- The package author(s).+author:              Romain Edelmann++-- An email address to which users can send suggestions, bug reports, and+-- patches.+maintainer:          romain.edelmann@gmail.com++-- A copyright notice.+copyright:           Copyright 2014 Romain Edelmann++category:            Math++build-type:          Simple++-- Constraint on the version of Cabal needed to build this package.+cabal-version:       >=1.8+++library+  -- Modules exported by the library.+  exposed-modules:     Data.Distribution,+                       Data.Distribution.Aggregator,+                       Data.Distribution.Core,+                       Data.Distribution.Domain.Coin,+                       Data.Distribution.Domain.Dice,+                       Data.Distribution.Measure,+                       Data.Distribution.Sample++  -- Modules included in this library but not exported.+  -- other-modules:++  -- Other library packages from which modules are imported.+  build-depends:       array >=0.4,+                       base >=4.5 && <5,+                       containers ==0.5.*,+                       MonadRandom ==0.1.*,+                       random ==1.0.*+