def compute_beta_and_R_components_from_FT( FTapp_ti_gs: List[ImproperProbabilityCumulativeFunction], FTnoapp_ti_gs: List[ImproperProbabilityCumulativeFunction], beta0_ti_gs: List[Callable[[float], float]], xi: float, tau_max: float, ) -> Tuple[ List[Callable[[float], float]], List[Callable[[float], float]], List[float], List[float], ]: """ Computes the app and no-app components of the suppressed infectiousness beta and the suppressed effective reproduction number R. :param FTapp_ti_gs: the list of test results times improper CDFs (one per severity component), for people with the app. :param FTnoapp_ti_gs: the list of test results times improper CDFs (one per severity component), for people without the app. :param beta0_ti_gs: the list of default infectiousness distributions (one per severity component). :param xi: the probability of self-isolation given a positive test result. :param tau_max: maximum relative time when doing numerical integrations. """ gs = range(len(FTapp_ti_gs)) # Values of severity G betaapp_ti_gs = [] betanoapp_ti_gs = [] Rapp_ti_gs = [] Rnoapp_ti_gs = [] for g in gs: rapp_ti_g = suppressed_beta_from_test_cdf( beta0_component=beta0_ti_gs[g], FT_component=FTapp_ti_gs[g], xi=xi ) betaapp_ti_gs.append(rapp_ti_g) rnoapp_ti_g = suppressed_beta_from_test_cdf( beta0_component=beta0_ti_gs[g], FT_component=FTnoapp_ti_gs[g], xi=xi ) betanoapp_ti_gs.append(rnoapp_ti_g) Rapp_ti_g = integrate(f=rapp_ti_g, a=0, b=tau_max) Rapp_ti_gs.append(Rapp_ti_g) Rnoapp_ti_g = integrate(f=rnoapp_ti_g, a=0, b=tau_max) Rnoapp_ti_gs.append(Rnoapp_ti_g) return betaapp_ti_gs, betanoapp_ti_gs, Rapp_ti_gs, Rnoapp_ti_gs
def test_R_suppression(self): _, beta0_gs = make_scenario_parameters_for_asymptomatic_symptomatic_model() beta0_ti_gs = [lambda tau: beta0_gs[0](0, tau), lambda tau: beta0_gs[1](0, tau)] xi = 0.8 # Any value in [0,1] will do tau_max = 30 FTapp_ti_gs = [ lambda tau: 0, lambda tau: 1 if tau >= 10 else 0, ] FTnoapp_ti_gs = [ lambda tau: 0, lambda tau: 1 if tau >= 20 else 0, ] ( betaapp_ti_gs, betanoapp_ti_gs, Rapp_ti_gs, Rnoapp_ti_gs, ) = compute_beta_and_R_components_from_FT( FTapp_ti_gs=FTapp_ti_gs, FTnoapp_ti_gs=FTnoapp_ti_gs, beta0_ti_gs=beta0_ti_gs, xi=xi, tau_max=tau_max, ) R0_gs = [integrate(f=beta0_ti_gs[g], a=0, b=tau_max) for g in [0, 1]] # No suppression for asymptomatic: assert all( beta0_ti_gs[0](tau) == betaapp_ti_gs[0](tau) == betanoapp_ti_gs[0](tau) for tau in (0, 3, 6, 9, 12, 15) ) assert Rapp_ti_gs[0] == Rnoapp_ti_gs[0] == R0_gs[0] # For symptomatic with app, suppression for tau >= 10 assert all(beta0_ti_gs[1](tau) == betaapp_ti_gs[1](tau) for tau in (0, 3, 6, 9)) assert all( betaapp_ti_gs[1](tau) == (1 - xi) * beta0_ti_gs[1](tau) for tau in (10, 13, 16, 19) ) assert (1 - xi) * R0_gs[1] <= Rapp_ti_gs[1] <= R0_gs[1] # For symptomatic without app, suppression for tau >= 20 assert all( beta0_ti_gs[1](tau) == betanoapp_ti_gs[1](tau) for tau in (0, 3, 6, 9, 12, 15, 18) ) assert all( betanoapp_ti_gs[1](tau) == (1 - xi) * beta0_ti_gs[1](tau) for tau in (20, 25) ) assert (1 - xi) * R0_gs[1] <= Rnoapp_ti_gs[1] <= R0_gs[1]
def plot_symptoms_onset_distribution(): tau_max = 30 step = 0.05 EtauS = integrate( lambda tau: (1 - FS(tau)), 0, tau_max ) # Expected time of symptoms onset for symptomatics print("E(τ^S) =", EtauS) plot_functions( fs=[FS], real_range=RealRange(x_min=0, x_max=tau_max, step=step), title="The CDF F^S of the symptoms onset time τ^S", )
def plot_and_integrate_infectiousness(): tau_max = 30 step = 0.05 integral_beta0 = integrate(beta0, 0, tau_max) print("The integral of β^0_0 is", integral_beta0) # This should (approximately) give back R0: assert round(integral_beta0 - R0, 5) == 0 plot_functions( fs=[beta0], real_range=RealRange(x_min=0, x_max=tau_max, step=step), title="The default infectiousness β^0_0", )
def plot_generation_time(): tau_max = 30 step = 0.05 print( "Expected default generation time: E(τ^C) =", integrate(lambda tau: tau * rho0(tau), 0, tau_max), ) plot_functions( fs=[rho0], real_range=RealRange(x_min=0, x_max=tau_max, step=step), title="The default generation time distribution ρ^0", )
def compute_time_evolution( scenario: Scenario, real_range: RealRange, n_iterations: int = 6, verbose: bool = True, ) -> List[StepData]: """ Given a Scenario, computes n_iterations steps of the algorithm, filling each time a StepData object and (if verbose=True) printing the relevant quantities computed. :param scenario: the Scenario object defining the input data of the mode. :param real_range: a RealRange object specifying the upper integration bound and the real numbers on which the functions and densities are sampled from one step to the next. :param n_iterations: the number of iterations. :param verbose: if True, the relevant quantities computed at each step are printed. :return: The list of StepData objects. """ tau_max = real_range.x_max step_data_list: List[StepData] = [] for i in range(0, n_iterations): gs = range(scenario.n_severities) # Values of severity G # Compute FAs components FAsapp_ti_gs = [ lambda tau, g=g: scenario.ssapp[g] * FS(tau) for g in gs ] FAsnoapp_ti_gs = [ lambda tau, g=g: scenario.ssnoapp[g] * FS(tau) for g in gs ] # Compute FA components if i == 0: t_i = scenario.t_0 FAapp_ti_gs = FAsapp_ti_gs FAnoapp_ti_gs = FAsnoapp_ti_gs else: previous_step_data = step_data_list[i - 1] t_i = previous_step_data.t + previous_step_data.EtauC FAapp_ti_gs, FAnoapp_ti_gs = compute_FA_from_FAs_and_previous_step_data( FAsapp_ti_gs=FAsapp_ti_gs, FAsnoapp_ti_gs=FAsnoapp_ti_gs, tildepapp_tim1=previous_step_data.tildepapp, tildeFTapp_tim1=previous_step_data.tildeFTapp, tildeFTnoapp_tim1=previous_step_data.tildeFTnoapp, EtauC_tim1=previous_step_data.EtauC, scapp=scenario.scapp, scnoapp=scenario.scnoapp, ) # Compute FT components FTapp_ti_gs, FTnoapp_ti_gs = compute_FT_from_FA_and_DeltaAT( FAapp_ti_gs=FAapp_ti_gs, FAnoapp_ti_gs=FAnoapp_ti_gs, p_DeltaATapp=scenario.p_DeltaATapp, p_DeltaATnoapp=scenario.p_DeltaATnoapp, ) # Compute beta, R components beta0_ti_gs = [ lambda tau, g=g: scenario.beta0_gs[g](t_i, tau) for g in gs ] ( rapp_ti_gs, rnoapp_ti_gs, Rapp_ti_gs, Rnoapp_ti_gs, ) = compute_beta_and_R_components_from_FT( FTapp_ti_gs=FTapp_ti_gs, FTnoapp_ti_gs=FTnoapp_ti_gs, beta0_ti_gs=beta0_ti_gs, xi=scenario.xi, tau_max=tau_max, ) # Compute aggregate beta (needed for EtauC), and R betaapp_ti = lambda tau: sum(scenario.p_gs[g] * rapp_ti_gs[g](tau) for g in gs) betanoapp_ti = lambda tau: sum(scenario.p_gs[g] * rnoapp_ti_gs[g](tau) for g in gs) beta_ti = lambda tau: scenario.papp(t_i) * betaapp_ti(tau) + ( 1 - scenario.papp(t_i)) * betanoapp_ti(tau) Rapp_ti = sum(scenario.p_gs[g] * Rapp_ti_gs[g] for g in gs) Rnoapp_ti = sum(scenario.p_gs[g] * Rnoapp_ti_gs[g] for g in gs) R_ti_gs = [ scenario.papp(t_i) * Rapp_ti_gs[g] + (1 - scenario.papp(t_i)) * Rnoapp_ti_gs[g] for g in gs ] R_ti = scenario.papp(t_i) * Rapp_ti + (1 - scenario.papp(t_i)) * Rnoapp_ti # Compute source-based probabilities and distributions EtauC_ti = integrate(f=lambda tau: tau * beta_ti(tau) / R_ti, a=0, b=tau_max) tildepapp_ti = scenario.papp(t_i) * Rapp_ti / R_ti tildep_ti_gs = [scenario.p_gs[g] * R_ti_gs[g] / R_ti for g in gs] tildeFTapp_ti = lambda tau: sum(tildep_ti_gs[g] * FTapp_ti_gs[g](tau) for g in gs) tildeFTnoapp_ti = lambda tau: sum(tildep_ti_gs[g] * FTnoapp_ti_gs[g] (tau) for g in gs) # Limits and Recap step_recap = f"step {i}, t_i={round2(t_i)}\n" if i != 0: FAsapp_ti_gs_infty = [FAsapp_ti_gs[g](tau_max) for g in gs] FAsnoapp_ti_gs_infty = [FAsnoapp_ti_gs[g](tau_max) for g in gs] FAsapp_ti_infty = sum(scenario.p_gs[g] * FAsapp_ti_gs_infty[g] for g in gs) FAsnoapp_ti_infty = sum(scenario.p_gs[g] * FAsnoapp_ti_gs_infty[g] for g in gs) FAs_ti_infty = (scenario.papp(t_i) * FAsapp_ti_infty + (1 - scenario.papp(t_i)) * FAsnoapp_ti_infty) FAs_recap = ( f" FAsapp_ti_gs(∞)={round2_list(FAsapp_ti_gs_infty)}\n" f" FAsnoapp_ti_gs(∞)={round2_list(FAsnoapp_ti_gs_infty)}\n" f" FAsapp_ti(∞)={round2(FAsapp_ti_infty)}\n" f" FAsnoapp_ti(∞)={round2(FAsnoapp_ti_infty)}\n" f" FAs_ti(∞)={round2(FAs_ti_infty)}\n") else: FAs_recap = "" FAapp_ti_gs_infty = [FAapp_ti_gs[g](tau_max) for g in gs] FAnoapp_ti_gs_infty = [FAnoapp_ti_gs[g](tau_max) for g in gs] FAapp_ti_infty = sum(scenario.p_gs[g] * FAapp_ti_gs_infty[g] for g in gs) FAnoapp_ti_infty = sum(scenario.p_gs[g] * FAnoapp_ti_gs_infty[g] for g in gs) FA_ti_infty = (scenario.papp(t_i) * FAapp_ti_infty + (1 - scenario.papp(t_i)) * FAnoapp_ti_infty) FA_recap = (f" FAapp_ti_gs(∞)={round2_list(FAapp_ti_gs_infty)}\n" f" FAnoapp_ti_gs(∞)={round2_list(FAnoapp_ti_gs_infty)}\n" f" FAapp_ti(∞)={round2(FAapp_ti_infty)}\n" f" FAnoapp_ti(∞)={round2(FAnoapp_ti_infty)}\n" f" FA_ti(∞)={round2(FA_ti_infty)}\n") FTapp_ti_gs_infty = [FTapp_ti_gs[g](tau_max) for g in gs] FTnoapp_ti_gs_infty = [FTnoapp_ti_gs[g](tau_max) for g in gs] FTapp_ti_infty = sum(scenario.p_gs[g] * FTapp_ti_gs_infty[g] for g in gs) FTnoapp_ti_infty = sum(scenario.p_gs[g] * FTnoapp_ti_gs_infty[g] for g in gs) FT_ti_infty = (scenario.papp(t_i) * FTapp_ti_infty + (1 - scenario.papp(t_i)) * FTnoapp_ti_infty) FT_recap = (f" FTapp_ti_gs(∞)={round2_list(FTapp_ti_gs_infty)}\n" f" FTnoapp_ti_gs(∞)={round2_list(FTnoapp_ti_gs_infty)}\n" f" FTapp_ti(∞)={round2(FTapp_ti_infty)}\n" f" FTnoapp_ti(∞)={round2(FTnoapp_ti_infty)}\n" f" FT_ti(∞)={round2(FT_ti_infty)}\n") R_recap = (f" Rapp_ti_gs={round2_list(Rapp_ti_gs)}\n" f" Rnoapp_ti_gs={round2_list(Rnoapp_ti_gs)}\n" f" Rapp_ti={round2(Rapp_ti)}\n" f" Rnoapp_ti={round2(Rnoapp_ti)}\n" f" R_ti_gs={round2_list(R_ti_gs)}\n" f" R_ti={round2(R_ti)}\n") other_recap = (f" papp_ti={round2(scenario.papp(t_i))}\n" f" tildepapp_ti={round2(tildepapp_ti)}\n" f" p_gs={round2_list(scenario.p_gs)}\n" f" tildep_ti_gs={round2_list(tildep_ti_gs)}\n" f" E(tauC_ti)={round2(EtauC_ti)} \n") current_step_data = StepData( real_range=real_range, t=t_i, papp=scenario.papp(t_i), tildepapp=tildepapp_ti, tildepgs=tildep_ti_gs, EtauC=EtauC_ti, FT_infty=FT_ti_infty, FTapp_infty=FTapp_ti_infty, FTnoapp_infty=FTnoapp_ti_infty, tildeFTapp=tildeFTapp_ti, tildeFTnoapp=tildeFTnoapp_ti, R=R_ti, Rapp=Rapp_ti, Rnoapp=Rnoapp_ti, ) step_data_list.append(current_step_data) if verbose: print(step_recap + FAs_recap + FA_recap + FT_recap + R_recap + other_recap) return step_data_list
def dependency_on_infectiousness_width_homogeneous_model_example(): """ Example of several computations of the limit Eff_∞ in homogeneous scenarios (i.e. with no app usage) in which the default distribution ρ^0 of the generation time is rescaled by different factors. """ infectiousness_rescale_factors = [0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8] expected_default_generation_times_list = [] Effinfty_values_list = [] for f in infectiousness_rescale_factors: def rescaled_rho0(tau): return (1 / f) * rho0(tau / f) assert round(integrate(rescaled_rho0, 0, tau_max), 5) == 1 EtauC0 = integrate( lambda tau: tau * rescaled_rho0(tau), 0, tau_max ) # Expected default generation time expected_default_generation_times_list.append(EtauC0) # gs = [asymptomatic, symptomatic] p_gs, beta0_gs = make_scenario_parameters_for_asymptomatic_symptomatic_model( rho0=rescaled_rho0 ) n_iterations = 6 scenario = make_homogeneous_scenario( p_gs=p_gs, beta0_gs=beta0_gs, t_0=0, ss=[0, 0.5], sc=0.7, xi=0.9, p_DeltaAT=DeltaMeasure(position=2), ) step_data_list = compute_time_evolution( scenario=scenario, real_range=RealRange(0, tau_max, integration_step), n_iterations=n_iterations, verbose=False, ) Rinfty = step_data_list[-1].R Effinfty = effectiveness_from_R(Rinfty) Effinfty_values_list.append(Effinfty) plt.ylim(0, 0.8) plt.grid(True) plt.plot( expected_default_generation_times_list, Effinfty_values_list, color="black", ), plt.xlabel("E(τ^{0,C})") plt.ylabel("Eff_∞") plt.title( "Effectiveness under rescaling of the default generation time distribution" ) plt.show()