{-# LANGUAGE RecordWildCards #-}
module Epidemic.BirthDeath
( configuration
, allEvents
) where
import Epidemic.Types.Parameter
import Epidemic.Types.Population
import Epidemic.Types.Events
import qualified Data.Vector as V
import System.Random.MWC
import System.Random.MWC.Distributions (bernoulli, exponential)
import Epidemic
import Epidemic.Utility
data BDRates =
BDRates Rate Rate
instance ModelParameters BDRates where
rNaught (BDRates birthRate deathRate) _ = Just $ birthRate / deathRate
eventRate (BDRates birthRate deathRate) _ = Just $ birthRate + deathRate
birthProb (BDRates birthRate deathRate) _ = Just $ birthRate / (birthRate + deathRate)
newtype BDPopulation =
BDPopulation People
deriving (Show)
instance Population BDPopulation where
susceptiblePeople _ = Nothing
infectiousPeople (BDPopulation people) = Just people
removedPeople _ = Nothing
isInfected (BDPopulation (People people)) = not $ V.null people
birthDeathRates :: Rate
-> Rate
-> Maybe BDRates
birthDeathRates birthRate deathRate
| birthRate >= 0 && deathRate >= 0 = Just $ BDRates birthRate deathRate
| otherwise = Nothing
configuration :: Time
-> (Rate, Rate)
-> Maybe (SimulationConfiguration BDRates BDPopulation)
configuration maxTime (birthRate, deathRate) =
let (seedPerson, newId) = newPerson initialIdentifier
bdPop = BDPopulation (People $ V.singleton seedPerson)
in do maybeBDRates <- birthDeathRates birthRate deathRate
if maxTime > 0 then Just (SimulationConfiguration maybeBDRates bdPop newId maxTime) else Nothing
randomBirthDeathEvent ::
BDRates
-> Time
-> BDPopulation
-> Integer
-> GenIO
-> IO (Time, EpidemicEvent, BDPopulation, Integer)
randomBirthDeathEvent (BDRates br dr) currTime (BDPopulation (People currPeople)) currId gen = do
delay <- exponential (fromIntegral (V.length currPeople) * (br + dr)) gen
isBirth <- bernoulli (br / (br + dr)) gen
(selectedPerson, unselectedPeople) <- randomPerson currPeople gen
return $
if isBirth
then let newTime = currTime + delay
(birthedPerson, newId) = newPerson currId
event = Infection newTime selectedPerson birthedPerson
in ( newTime
, event
, BDPopulation (People $ V.cons birthedPerson currPeople)
, newId)
else let newTime = currTime + delay
event = Removal newTime selectedPerson
in (newTime, event, BDPopulation (People unselectedPeople), currId)
allEvents ::
BDRates
-> Time
-> (Time, [EpidemicEvent], BDPopulation, Integer)
-> GenIO
-> IO (Time, [EpidemicEvent], BDPopulation, Integer)
allEvents rates maxTime currState@(currTime, currEvents, currPop, currId) gen =
if isInfected currPop
then do
(newTime, event, newPop, newId) <-
randomBirthDeathEvent rates currTime currPop currId gen
if newTime < maxTime
then allEvents
rates
maxTime
(newTime, event : currEvents, newPop, newId)
gen
else return currState
else return currState