prob-fx-0.1.0.0: examples/SIR.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators, TypeApplications #-}
{-# LANGUAGE OverloadedLabels #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Redundant return" #-}
module SIR where
import Prog
import Effects.Writer
import Model
import Inference.SIM as SIM
import Inference.MH as MH
import Sampler
import Env
import Control.Monad
import HMM
-- ** The SIR model
data Popl = Popl {
s :: Int, -- ^ Number of people susceptible to infection
i :: Int, -- ^ Number of people currently infected
r :: Int -- ^ Number of people recovered from infection
} deriving Show
type Reported = Int
-- | SIR transition model
transSI :: TransModel env ts Double Popl
transSI beta (Popl s i r) = do
let pop = s + i + r
dN_SI <- binomial' s (1 - exp ((-beta * fromIntegral i) / fromIntegral pop))
return $ Popl (s - dN_SI) (i + dN_SI) r
transIR :: TransModel env ts Double Popl
transIR gamma (Popl s i r) = do
dN_IR <- binomial' i (1 - exp (-gamma))
return $ Popl s (i - dN_IR) (r + dN_IR)
data TransParamsSIR = TransParamsSIR {
betaP :: Double, -- ^ Mean contact rate between susceptible and infected people
gammaP :: Double -- ^ Mean recovery rate
}
transSIR :: Member (Writer [Popl]) es -- || Writer effect from Section 5.5
=> TransModel env es TransParamsSIR Popl
transSIR (TransParamsSIR beta gamma) sir = do
sir' <- (transSI beta >=> transIR gamma) sir
tellM [sir']
return sir'
-- | SIR observation model
type ObsParams = Double
obsSIR :: Observable env "𝜉" Int
=> ObsModel env ts Double Popl Reported
obsSIR rho (Popl _ i _) = do
i <- poisson (rho * fromIntegral i) #𝜉
return i
-- | SIR transition prior
transPriorSIR :: Observables env '["β", "γ"] Double
=> Model env ts TransParamsSIR
transPriorSIR = do
pBeta <- gamma 2 1 #β
pGamma <- gamma 1 (1/8) #γ
return (TransParamsSIR pBeta pGamma)
-- | SIR observation prior
obsPriorSIR :: Observables env '["ρ"] Double
=> Model env ts ObsParams
obsPriorSIR = do
pRho <- beta 2 7 #ρ
return pRho
-- | SIR as HMM
hmmSIR :: (Member (Writer [Popl]) es, Observable env "𝜉" Int, Observables env '["ρ", "β", "γ"] Double)
=> Int -> Popl -> Model env es Popl
hmmSIR = hmmGen transPriorSIR obsPriorSIR transSIR obsSIR
hmmSIR' :: (Observables env '["𝜉"] Int , Observables env '[ "β" , "γ" , "ρ"] Double) => Int -> Popl -> Model env es (Popl, [Popl])
hmmSIR' n = handleWriterM . hmmSIR n
type SIRenv = '["β" := Double, "γ" := Double, "ρ" := Double, "𝜉" := Int]
-- ** Simulating from SIR model: ([(s, i, r)], [𝜉])
simulateSIR :: Sampler ([(Int, Int, Int)], [Reported])
simulateSIR = do
let sim_env_in = #β := [0.7] <:> #γ := [0.009] <:> #ρ := [0.3] <:> #𝜉 := [] <:> nil
sir_0 = Popl {s = 762, i = 1, r = 0}
((_, sir_trace), sim_env_out) <- SIM.simulate (hmmSIR' 100) sim_env_in sir_0
let 𝜉s :: [Reported] = get #𝜉 sim_env_out
sirs = map (\(Popl s i recov) -> (s, i, recov)) sir_trace
return (sirs, 𝜉s)
-- ** MH inference from SIR model: ([ρ], [β])
inferSIR :: Sampler ([Double], [Double])
inferSIR = do
𝜉s <- snd <$> simulateSIR
let mh_env_in = #β := [] <:> #γ := [0.0085] <:> #ρ := [] <:> #𝜉 := 𝜉s <:> nil
sir_0 = Popl {s = 762, i = 1, r = 0}
mhTrace <- MH.mh 50000 (hmmSIR' 100) (sir_0, mh_env_in) ["β", "ρ"]
let ρs = concatMap (get #ρ) mhTrace
βs = concatMap (get #β) mhTrace
return (ρs, βs)
-- ** Modular Extensions to the SIR Model
{- Note that the implementations below aren't as modular as we would like, due to having to redefine the data types Popl and TransParams when adding new variables to the SIR model. The file "SIRModular.hs" shows how one could take steps to resolve this by using extensible records. -}
-- || SIRS (resusceptible) model
data TransParamsSIRS = TransParamsSIRS {
betaP_SIRS :: Double, -- ^ Mean contact rate between susceptible and infected people
gammaP_SIRS :: Double, -- ^ Mean recovery rate
etaP_SIRS :: Double -- ^ Rate of resusceptible
}
-- | SIRS transition model
transRS :: Double -> Popl -> Model env ts Popl
transRS eta (Popl s i r) = do
dN_RS <- binomial' r (1 - exp (-eta))
return $ Popl (s + dN_RS) i (r - dN_RS)
transSIRS :: Member (Writer [Popl]) es
=> TransModel env es TransParamsSIRS Popl
transSIRS (TransParamsSIRS beta gamma eta) sir = do
sir' <- (transSI beta >=> transIR gamma >=> transRS eta) sir
tellM [sir']
return sir'
-- | SIR transition prior
transPriorSIRS :: Observables env '["β", "η", "γ"] Double
=> Model env ts TransParamsSIRS
transPriorSIRS = do
TransParamsSIR pBeta pGamma <- transPriorSIR
pEta <- gamma 1 (1/8) #η
return (TransParamsSIRS pBeta pGamma pEta)
-- | SIRS as HMM
hmmSIRS :: (Observables env '["𝜉"] Int, Observables env '["β", "η", "γ", "ρ"] Double) => Int -> Popl -> Model env ts (Popl, [Popl])
hmmSIRS n = handleWriterM . hmmGen transPriorSIRS obsPriorSIR transSIRS obsSIR n
-- || (Section 3.2, Fig 4b) SIM from SIRS model: ([(s, i, r)], [𝜉])
simulateSIRS :: Sampler ([(Int, Int, Int)], [Reported])
simulateSIRS = do
let sim_env_in = #β := [0.7] <:> #γ := [0.009] <:> #η := [0.05] <:> #ρ := [0.3] <:> #𝜉 := [] <:> nil
sir_0 = Popl {s = 762, i = 1, r = 0}
((_, sir_trace), sim_env_out) <- SIM.simulate (hmmSIRS 100) sim_env_in sir_0
let 𝜉s :: [Reported] = get #𝜉 sim_env_out
sirs = map (\(Popl s i recov) -> (s, i, recov)) sir_trace
return (sirs, 𝜉s)
-- || SIRSV (resusceptible + vacc) model
data TransParamsSIRSV = TransParamsSIRSV {
betaP_SIRSV :: Double, -- ^ Mean contact rate between susceptible and infected people
gammaP_SIRSV :: Double, -- ^ Mean recovery rate
etaP_SIRSV :: Double, -- ^ Rate of resusceptible
omegaP_SIRSV :: Double -- ^ Vaccination rate
}
data PoplV = PoplV {
s' :: Int,
i' :: Int,
r' :: Int,
v' :: Int
} deriving Show
-- | SIRSV transition models
transSI' :: TransModel env ts Double PoplV
transSI' beta (PoplV s i r v) = do
let pop = s + i + r + v
dN_SI <- binomial' s (1 - exp ((-beta * fromIntegral i) / fromIntegral pop))
return $ PoplV (s - dN_SI) (i + dN_SI) r v
transIR' :: TransModel env ts Double PoplV
transIR' gamma (PoplV s i r v) = do
dN_IR <- binomial' i (1 - exp (-gamma))
return $ PoplV s (i - dN_IR) (r + dN_IR) v
transRS' :: TransModel env es Double PoplV
transRS' eta (PoplV s i r v) = do
dN_RS <- binomial' r (1 - exp (-eta))
return $ PoplV (s + dN_RS) i (r - dN_RS) v
transSV' :: TransModel env es Double PoplV
transSV' omega (PoplV s i r v) = do
dN_SV <- binomial' s (1 - exp (-omega))
return $ PoplV (s - dN_SV) i r (v + dN_SV )
transSIRSV :: Member (Writer [PoplV]) ts => TransModel env ts TransParamsSIRSV PoplV
transSIRSV (TransParamsSIRSV beta gamma omega eta) sirv = do
sirv' <- (transSI' beta >=>
transIR' gamma >=>
transRS' eta >=>
transSV' omega) sirv
tellM [sirv']
return sirv'
-- | SIRSV transition prior
transPriorSIRSV :: Observables env '["β", "γ", "ω", "η"] Double
=> Model env ts TransParamsSIRSV
transPriorSIRSV = do
TransParamsSIRS pBeta pGamma pEta <- transPriorSIRS
pOmega <- gamma 1 (1/16) #ω
return (TransParamsSIRSV pBeta pGamma pEta pOmega)
-- | SIRSV observation model
obsSIRSV :: Observable env "𝜉" Int
=> ObsModel env ts Double PoplV Reported
obsSIRSV rho (PoplV _ i _ v) = do
i <- poisson (rho * fromIntegral i) #𝜉
return i
-- | SIRSV as HMM
hmmSIRSV :: (Observables env '["𝜉"] Int, Observables env '["β", "γ", "η", "ω", "ρ"] Double) => Int -> PoplV -> Model env ts (PoplV, [PoplV])
hmmSIRSV n = handleWriterM . hmmGen transPriorSIRSV obsPriorSIR transSIRSV obsSIRSV n
-- || Simulate from SIRSV model : ([(s, i, r, v)], [𝜉])
simulateSIRSV :: Sampler ([(Int, Int, Int, Int)], [Reported])
simulateSIRSV = do
let sim_env_in = #β := [0.7] <:> #γ := [0.009] <:> #η := [0.05] <:> #ω := [0.02] <:> #ρ := [0.3] <:> #𝜉 := [] <:> nil
sirv_0 = PoplV {s' = 762, i' = 1, r' = 0, v' = 0}
((_, sirv_trace), sim_env_out) <- SIM.simulate (hmmSIRSV 100) sim_env_in sirv_0
let 𝜉s :: [Reported] = get #𝜉 sim_env_out
sirvs = map (\(PoplV s i recov v) -> (s, i, recov, v)) sirv_trace
return (sirvs, 𝜉s)