covidSIR / src /sampler.py
SnoopKilla's picture
Gradio APP
406ac25
raw
history blame
6.64 kB
from src.utility_functions import log_pi_lambda, log_pi_t
import numpy as np
def update_lambda(lam, t, s, i, P, sigma, alpha, beta, phi):
# This function updates the parameter vector lambda.
# INPUT:
# - lam: array of the values of lambda;
# - t: array of the breakpoints;
# - s: array of susceptible individuals during time;
# - i: array of infected individuals during time;
# - P: total number of individuals;
# - sigma: algorithm parameter for the proposal of a new candidate lambda;
# - alpha, beta: hyperparameters of the prior of lambda;
# - phi parameter phi of the model.
# OUTPUT:
# - lam: update array;
# - accept: number of acceted candidates.
# NOTES: The update is done component-wise in a sequential manner.
current = np.copy(lam) # Get the current state of the chain.
candidate = np.copy(current) # Initialize the new candidate.
# For every component of the parameter vector, we tweak such component
# according to the chosen proposal and then update the chain according
# to the computed acceptance rate.
accepted = 0 # Initialize the count of accepted candidates.
for j in range(current.shape[0]):
# Tweak the j-th component.
candidate[j] = candidate[j] + sigma * np.random.normal()
# Compute the acceptance rate.
log_alpha = (log_pi_lambda(candidate, t, s, i, P, alpha, beta, phi)
- log_pi_lambda(current, t, s, i, P, alpha, beta, phi))
# If the candidate is accepted, we move the chain (current = candidate)
# and increase the count of accepted candidates. Otherwise, we reject
# the candidate and the chain does not move from the current state
# (candidate = current).
if log_alpha > np.log(np.random.uniform()):
current = np.copy(candidate)
accepted = accepted + 1
else:
candidate = np.copy(current)
return current.reshape(-1, 1), accepted
def update_t(lam, t, s, i, P, M, phi):
# This function updates the parameter vector lambda.
# INPUT:
# - lam: array of the values of lambda;
# - t: array of the breakpoints;
# - s: array of susceptible individuals during time;
# - i: array of infected individuals during time;
# - P: total number of individuals;
# - M: algorithm parameter for the proposal of a new candidate t;
# - phi parameter phi of the model.
# OUTPUT:
# - lam: update array;
# - accept: number of acceted candidates.
# NOTES: The update is done component-wise in a sequential manner.
current = np.copy(t) # Get the current state of the chain.
candidate = np.copy(current) # Initialize the new candidate.
# For every component of the parameter vector, we tweak such component
# according to the chosen proposal and then update the chain according
# to the computed acceptance rate.
accepted = 0 # Initialize the count of accepted candidates.
for j in range(current.shape[0]):
# Tweak the j-th component.
candidate[j] = candidate[j] + np.random.choice(np.arange(-M, M + 1))
# Compute the acceptance rate.
log_alpha = (log_pi_t(lam, candidate, s, i, P, phi)
- log_pi_t(lam, current, s, i, P, phi))
# If the candidate is accepted, we move the chain (current = candidate)
# and increase the count of accepted candidates. Otherwise, we reject
# the candidate and the chain does not move from the current state
# (candidate = current).
if log_alpha > np.log(np.random.uniform()):
current = np.copy(candidate)
accepted = accepted + 1
else:
candidate = np.copy(current)
return current.reshape(-1, 1), accepted
def mcmc_sampler(s, i, d, P, n_iterations, burnin, M, sigma,
alpha, beta, a, b, phi):
# This function implement the hybrid MCMC sampler.
# INPUT:
# - s: array of susceptible individuals during time;
# - i: array of infected individuals during time;
# - d: number of breakpoints;
# - P: total number of individuals;
# - n_iterations: number of iterations for the algorithm;
# - burnin: number of burnin iterations to discard;
# - M: algorithm parameter for the proposal of a new candidate t;
# - sigma: algorithm parameter for the proposal of a new candidate lambda;
# - alpha, beta: hyperparameters of the prior of lambda;
# - a, b: hyperparameters of the prior of p;
# - phi: parameter phi of the model.
# OUTPUT:
# - p: simulated chain for the probability of removal from
# infected population;
# - lam: simulated chain for lambda;
# - t: simulated chain for the breakpoints.
T = s.shape[0] - 1 # Index of the final time instant.
# Initialize the parameters.
# The initial value of p is drawn from the prior distribution.
p = np.random.beta(a, b, size=(1, 1))
# Each of the d breakpoints (t_i) is drawn randomly (without replacement)
# between 1 and T-1. The obtained vector is then sorted to make sure
# that t_1 < t_2 < ... < t_d.
t = np.sort(np.random.choice(np.arange(1, T), size=d-1, replace=False))
t = t.reshape(-1, 1)
# Each of the lambda_i's is drawn independently from
# its prior distribution.
lam = np.random.gamma(alpha, beta)
lam = lam.reshape(-1, 1)
# Compute the hyperparameters of the posterior of p.
a_new = a + i[0] - i[-1] + s[0] - s[-1]
b_new = b + np.sum(i[1:]) + s[-1] - s[0]
# Initialize the count of accepted candidates for lambda and t.
a_lam = 0
a_t = 0
# Run the chain
for _ in range(n_iterations):
# Update p by sampling from its posterior.
p = np.hstack((p, np.random.beta(a_new, b_new, size=(1, 1))))
# Update lam via Metropolis-Hastings step.
new_lam, accepted_lam = update_lambda(lam[:, -1], t[:, -1], s, i, P,
sigma, alpha, beta, phi)
# Update t via Metropolis-Hastings step.
new_t, accepted_t = update_t(lam[:, -1], t[:, -1], s, i, P, M, phi)
lam = np.hstack((lam, new_lam))
t = np.hstack((t, new_t))
# Update the counts of accepted candidates for lambda and t.
a_lam = a_lam + accepted_lam
a_t = a_t + accepted_t
# Compute the acceptance rates for lambda and t.
lam_ar = a_lam / n_iterations / d
t_ar = a_t / n_iterations / (d-1)
# Discard burn-in iterations.
p = p[:, burnin:]
lam = lam[:, burnin:]
t = t[:, burnin:]
return p, lam, t, lam_ar, t_ar