commit 6cbfa45b988907e94ca7826072ccced8b1317e42
parent a29f755f45537a863a114685e465791ecf4bcea7
Author: Jared Tobin <jared@jtobin.ca>
Date: Mon, 8 Feb 2016 23:15:53 +1300
More functional approach.
Diffstat:
4 files changed, 27 insertions(+), 56 deletions(-)
diff --git a/lib/Numeric/Sampling.hs b/lib/Numeric/Sampling.hs
@@ -20,9 +20,10 @@ module Numeric.Sampling (
import qualified Control.Foldl as F
import Control.Monad.Primitive (PrimMonad, PrimState)
import qualified Data.Foldable as Foldable
+import Data.Function (on)
+import Data.List (sortBy)
import Data.Maybe (fromJust)
import Data.Vector (Vector)
-import qualified Data.Vector as V
import Numeric.Sampling.Internal
import System.Random.MWC
@@ -48,14 +49,14 @@ sampleIO n xs = do
-- | (/O(n log n)/) Sample uniformly with replacement (bootstrap).
resample
:: (PrimMonad m, Foldable f)
- => Int -> f a -> Gen (PrimState m) -> m (Vector a)
+ => Int -> f a -> Gen (PrimState m) -> m [a]
resample n xs = presample n weighted where
weight = recip (F.fold F.genericLength xs)
weighted = zip (repeat weight) (Foldable.toList xs)
{-# INLINABLE resample #-}
-- | (/O(n log n)/) 'resample' specialized to IO.
-resampleIO :: (Foldable f) => Int -> f a -> IO (Vector a)
+resampleIO :: (Foldable f) => Int -> f a -> IO [a]
resampleIO n xs = do
gen <- createSystemRandom
resample n xs gen
@@ -64,31 +65,32 @@ resampleIO n xs = do
-- | (/O(n log n)/) Unequal probability resampling.
presample
:: (PrimMonad m, Foldable f)
- => Int -> f (Double, a) -> Gen (PrimState m) -> m (Vector a)
+ => Int -> f (Double, a) -> Gen (PrimState m) -> m [a]
presample n weighted gen
- | n <= 0 = return V.empty
+ | n <= 0 = return []
| otherwise = do
- let vweighted = V.fromList $ Foldable.toList weighted
- sorted <- mutableSortByProbability vweighted
- let probs = drop 1 (F.scan (F.premap fst F.sum) (V.toList sorted))
- cdf = V.zip (V.fromList probs) (V.map snd sorted)
- accumulateSample n cdf gen
+ let (bprobs, vals) = unzip $ sortProbs weighted
+ probs = drop 1 (F.scan F.sum bprobs)
+ cumulative = zip probs vals
+ computeSample n cumulative gen
where
- accumulateSample
- :: (PrimMonad m)
- => Int -> Vector (Double, a) -> Gen (PrimState m) -> m (Vector a)
- accumulateSample size xs g = go V.empty size where
+ computeSample
+ :: PrimMonad m => Int -> [(Double, a)] -> Gen (PrimState m) -> m [a]
+ computeSample size xs g = go [] size where
go !acc s
- | s <= 0 = return $! acc
+ | s <= 0 = return acc
| otherwise = do
z <- uniform g
- let pair = F.fold (F.find ((>= z) . fst)) xs
- result = snd . fromJust $ pair -- FIXME
- go (V.cons result acc) (pred s)
+ let (_, v) = fromJust $ F.fold (F.find ((>= z) . fst)) xs
+ go (v:acc) (pred s)
+
+ sortProbs :: (Foldable f, Ord a) => f (a, b) -> [(a, b)]
+ sortProbs = sortBy (compare `on` fst) . Foldable.toList
+
{-# INLINABLE presample #-}
-- | (/O(n log n)/) 'presample' specialized to IO.
-presampleIO :: (Foldable f) => Int -> f (Double, a) -> IO (Vector a)
+presampleIO :: (Foldable f) => Int -> f (Double, a) -> IO [a]
presampleIO n weighted = do
gen <- createSystemRandom
presample n weighted gen
diff --git a/lib/Numeric/Sampling/Functional.hs b/lib/Numeric/Sampling/Functional.hs
@@ -1,39 +1,18 @@
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE DeriveFunctor #-}
-module Numeric.Sampling.Functional (
- resample
- , resampleIO
- ) where
+module Numeric.Sampling.Functional where
import qualified Control.Foldl as F
import Control.Monad.Primitive (PrimMonad, PrimState)
import qualified Data.Foldable as Foldable (toList)
import Data.Function (on)
-import Data.List.Ordered (mergeBy)
+import Data.List (sortBy)
import Data.Maybe (fromJust)
import System.Random.MWC
-data TreeF a r =
- EmptyF
- | LeafF a
- | NodeF r r
- deriving Functor
-
sortProbs :: (Foldable f, Ord a) => f (a, b) -> [(a, b)]
-sortProbs = hylo alg coalg . Foldable.toList where
- alg EmptyF = []
- alg (LeafF x) = [x]
- alg (NodeF l r) = mergeBy (compare `on` fst) l r
-
- coalg [] = EmptyF
- coalg [x] = LeafF x
- coalg xs = NodeF l r where
- (l, r) = splitAt (length xs `div` 2) xs
-
- hylo :: Functor f => (f a -> a) -> (b -> f b) -> b -> a
- hylo f g = h where h = f . fmap h . g
+sortProbs = sortBy (compare `on` fst) . Foldable.toList
presample
:: (PrimMonad m, Foldable f)
@@ -55,20 +34,11 @@ presample n weighted gen
z <- uniform g
let (_, v) = fromJust $ F.fold (F.find ((>= z) . fst)) xs
go (v:acc) (pred s)
+{-# INLINABLE presample #-}
presampleIO :: Foldable f => Int -> f (Double, a) -> IO [a]
presampleIO n weighted = do
gen <- createSystemRandom
presample n weighted gen
+{-# INLINABLE presampleIO #-}
-resample
- :: (PrimMonad m, Foldable f) => Int -> f a -> Gen (PrimState m) -> m [a]
-resample n xs gen = do
- let len = F.fold F.genericLength xs
- weighted = zip (repeat (1 / len)) (Foldable.toList xs)
- presample n weighted gen
-
-resampleIO :: Foldable f => Int -> f a -> IO [a]
-resampleIO n xs = do
- gen <- createSystemRandom
- resample n xs gen
diff --git a/sampling.cabal b/sampling.cabal
@@ -37,7 +37,6 @@ library
base < 5
, foldl
, mwc-random
- , data-ordlist
, primitive
, vector
, vector-algorithms
diff --git a/src/Main.hs b/src/Main.hs
@@ -2,7 +2,7 @@
module Main where
-import Numeric.Sampling.Functional
+import Numeric.Sampling
main :: IO ()
main = do