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
예제 #7
0
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()