prob-fx-0.1.0.0: examples/SIRModular.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators, TypeApplications #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Redundant return" #-}
module SIRModular where
import qualified Data.Extensible as Extensible
import Data.Extensible hiding (Member)
import Prog
import Control.Lens hiding ((:>))
import Effects.Writer
import Model
import Control.Monad
import Env
import HMM
import Data.Extensible (Associated)
import GHC.TypeLits
import Data.Kind (Constraint)
type family Lookups env (ks :: [Symbol]) a :: Constraint where
Lookups env (x ': xs) a = (Lookup env x a, Lookups env xs a)
Lookups env '[] a = ()
mkField "s i r v"
type Reported = Int
{- SIR model using extensible records -}
-- | SIR transition model
transSI :: Lookups popl '["s", "i", "r"] Int => TransModel env ts Double (Record popl)
transSI beta popl = do
let (s_0, i_0, r_0 ) = (popl ^. s, popl ^. i, popl ^. r)
pop = s_0 + i_0 + r_0
dN_SI <- binomial' s_0 (1 - exp ((-beta * fromIntegral i_0) / fromIntegral pop))
return $ popl & s .~ (s_0 - dN_SI)
& i .~ (i_0 + dN_SI)
transIR :: Lookups popl '["i", "r"] Int => TransModel env ts Double (Record popl)
transIR gamma popl = do
let (i_0, r_0) = (popl ^. i, popl ^. r)
dN_IR <- binomial' i_0 (1 - exp (-gamma))
return $ popl & i .~ (i_0 - dN_IR)
& r .~ (r_0 + dN_IR)
transSIR :: (Member (Writer [Record popl]) ts, Lookups popl '["s", "i", "r"] Int)
=> TransModel env ts (Double, Double) (Record popl)
transSIR (beta, gamma) popl = do
popl <- (transSI beta >=> transIR gamma) popl
tellM [popl]
return popl
-- | SIR observation model
type ObsParams = Double
obsSIR :: Lookup s "i" Int => Observable env "𝜉" Int
=> ObsModel env ts Double (Record s) Reported
obsSIR rho popl = do
let i_0 = popl ^. i
poisson (rho * fromIntegral i_0) #𝜉
-- | SIR transition prior
transPriorSIR :: Observables env '["β", "γ"] Double
=> Model env ts (Double, Double)
transPriorSIR = do
pBeta <- gamma 2 1 #β
pGamma <- gamma 1 (1/8) #γ
return (pBeta, pGamma)
-- | SIR observation prior
obsPriorSIR :: Observables env '["ρ"] Double
=> Model env ts ObsParams
obsPriorSIR = beta 2 7 #ρ
-- | SIR as HMM
hmmSIR :: (Member (Writer [Record popl]) es,
Lookups popl '["s", "i", "r"] Int, Observable env "𝜉" Int, Observables env '["ρ", "β", "γ"] Double)
=> Int -> Record popl -> Model env es (Record popl, [Record popl])
hmmSIR n = handleWriterM . hmmGen transPriorSIR obsPriorSIR transSIR obsSIR n
{- SIRS (resusceptible) model -}
-- | SIRS transition model
transRS :: Lookups popl '["s", "r"] Int => TransModel env ts Double (Record popl)
transRS eta popl = do
let (r_0, s_0) = (popl ^. r, popl ^. s)
dN_RS <- binomial' r_0 (1 - exp (-eta))
return $ popl & r .~ (r_0 - dN_RS)
& s .~ (s_0 + dN_RS)
transSIRS :: Lookups popl '["s", "i", "r"] Int => TransModel env es (Double, Double, Double) (Record popl)
transSIRS (beta, gamma, eta) = transSI beta >=> transIR gamma >=> transRS eta
-- | SIRS transition prior
transPriorSIRS :: Observables env '["β", "η", "γ"] Double
=> Model env ts (Double, Double, Double)
transPriorSIRS = do
(pBeta, pGamma) <- transPriorSIR
pEta <- gamma 1 (1/8) #η
return (pBeta, pGamma, pEta)
-- | SIRS as HMM
hmmSIRS :: (Member (Writer [Record popl]) es,
Lookups popl '["s", "i", "r"] Int,
Observables env '["𝜉"] Int, Observables env '["β", "η", "γ", "ρ"] Double)
=> Int -> Record popl -> Model env es (Record popl, [Record popl])
hmmSIRS n = handleWriterM . hmmGen transPriorSIRS obsPriorSIR transSIRS obsSIR n
{- SIRSV (resusceptible + vacc) model -}
-- | SIRSV transition model
transSV :: Lookups popl '["s", "v"] Int => TransModel env es Double (Record popl)
transSV omega popl = do
let (s_0, v_0) = (popl ^. s, popl ^. v)
dN_SV <- binomial' s_0 (1 - exp (-omega))
return $ popl & s .~ (s_0 - dN_SV)
& v .~ (v_0 + dN_SV)
transSIRSV :: Lookups popl '["s", "i", "r", "v"] Int => TransModel env ts (Double, Double, Double, Double) (Record popl)
transSIRSV (beta, gamma, eta, omega) =
transSI beta >=> transIR gamma >=> transRS eta >=> transSV omega
-- | SIRSV transition prior
transPriorSIRSV :: Observables env '["β", "γ", "ω", "η"] Double
=> Model env ts (Double, Double, Double, Double)
transPriorSIRSV = do
(pBeta, pGamma, pEta) <- transPriorSIRS
pOmega <- gamma 1 (1/16) #ω
return (pBeta, pGamma, pEta, pOmega)
-- | SIRSV as HMM
hmmSIRSV :: (Member (Writer [Record popl]) es,
Lookups popl '["s", "i", "r", "v"] Int,
Observables env '["𝜉"] Int, Observables env '["β", "η", "γ", "ω", "ρ"] Double)
=> Int -> Record popl -> Model env es (Record popl, [Record popl])
hmmSIRSV n = handleWriterM . hmmGen transPriorSIRSV obsPriorSIR transSIRSV obsSIR n