@@ -21,7 +21,7 @@ data TickInfo
21 , _tickInfo_alreadyElapsed :: NominalDiffTime
21 , _tickInfo_alreadyElapsed :: NominalDiffTime
22 -- ^ Amount of time already elapsed in the current tick period.
22 -- ^ Amount of time already elapsed in the current tick period.
24− deriving (Eq)
24+ deriving (Eq, Show)
26-- | Special case of tickLossyFrom that uses the post-build event to start the
26-- | Special case of tickLossyFrom that uses the post-build event to start the
27-- tick thread.
27-- tick thread.
@@ -98,29 +98,50 @@ inhomogeneousPoissonFrom
98 -> Event t a
98 -> Event t a
99 -> m (Event t TickInfo)
99 -> m (Event t TickInfo)
100inhomogeneousPoissonFrom rnd rate maxRate t0 e = do
100inhomogeneousPoissonFrom rnd rate maxRate t0 e = do
102+ -- Create a thread for producing homogeneous poisson events
103+ -- along with random Doubles (usage of Double's explained below)
101 ticksWithRateRand <- performEventAsync $
104 ticksWithRateRand <- performEventAsync $
102 fmap callAtNextInterval e
105 fmap callAtNextInterval e
107+ -- Filter homogeneous events according to associated
108+ -- random values and the current rate parameter
103 return $ attachWithMaybe filterFun rate ticksWithRateRand
109 return $ attachWithMaybe filterFun rate ticksWithRateRand
113+ -- Inhomogeneous poisson processes are built from faster
114+ -- homogeneous ones by randomly dropping events from the
115+ -- fast process. For each fast homogeneous event, choose
116+ -- a uniform random sample from (0, rMax). If the
117+ -- inhomogeneous rate at this moment is greater than the
118+ -- random sample, then keep this event, otherwise drop it
107 filterFun :: Double -> (TickInfo, Double) -> Maybe TickInfo
119 filterFun :: Double -> (TickInfo, Double) -> Maybe TickInfo
108 filterFun r (tInfo, p)
120 filterFun r (tInfo, p)
109 | r >= p = Just tInfo
121 | r >= p = Just tInfo
110 | otherwise = Nothing
122 | otherwise = Nothing
112− callAtNextInterval _ cb = void $ liftIO $ forkIO $ go rnd cb
124+ callAtNextInterval _ cb = void $ liftIO $ forkIO $ go t0 rnd cb 0
114− go lastGen cb = do
126+ go tTargetLast lastGen cb lastN = do
115 t <- getCurrentTime
127 t <- getCurrentTime
129+ -- Generate random numbers for this poisson interval (u)
130+ -- and sample-retention likelihood (p)
116− let (u, nextGen) = randomR (0,1) lastGen
131+ let (u, nextGen) = randomR (0,1) lastGen
117 (p :: Double, nextGen') = randomR (0,maxRate) nextGen
132 (p :: Double, nextGen') = randomR (0,maxRate) nextGen
134+ -- Inter-event interval is drawn from exponential
135+ -- distribution accourding to u
118− dt = realToFrac $ -1 * log(u)/maxRate :: NominalDiffTime
136+ let dt = realToFrac $ -1 * log(u)/maxRate :: NominalDiffTime
119− offset = t `diffUTCTime` t0
137+ offset = t `diffUTCTime` t0
120− (n, alreadyElapsed) = offset `divMod'` dt
139+ alreadyElapsed = diffUTCTime t tTargetLast
140+ tTarget = addUTCTime dt tTargetLast
141+ thisDelay = realToFrac $ diffUTCTime tTarget t :: Double
121− threadDelay $ ceiling $ (dt - alreadyElapsed) * 1000000
142+ threadDelay $ ceiling $ thisDelay * 1000000
122− void $ cb $ (TickInfo t n alreadyElapsed, p)
143+ void $ cb $ (TickInfo t nEvents alreadyElapsed, p)
123− go nextGen' cb
144+ go tTarget nextGen' cb nEvents
125-- | Send events with inhomogeneous Poisson timing with the given basis
146-- | Send events with inhomogeneous Poisson timing with the given basis
126-- and variable rate. Provide a maxRate that you expect to support
147-- and variable rate. Provide a maxRate that you expect to support