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 +175/−0
- Data/Distribution/Aggregator.hs +107/−0
- Data/Distribution/Core.hs +388/−0
- Data/Distribution/Domain/Coin.hs +46/−0
- Data/Distribution/Domain/Dice.hs +72/−0
- Data/Distribution/Measure.hs +153/−0
- Data/Distribution/Sample.hs +196/−0
- LICENSE +202/−0
- Setup.hs +2/−0
- distribution.cabal +65/−0
+ 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.*+