def test_basic_simulation_stochastic(data_api_stochastic):
    network, _ = np.createNetworkOfPopulation(
        data_api_stochastic.read_table("human/compartment-transition",
                                       "compartment-transition"),
        data_api_stochastic.read_table("human/population", "population"),
        data_api_stochastic.read_table("human/commutes", "commutes"),
        data_api_stochastic.read_table("human/mixing-matrix", "mixing-matrix"),
        data_api_stochastic.read_table("human/infectious-compartments",
                                       "infectious-compartments"),
        data_api_stochastic.read_table("human/infection-probability",
                                       "infection-probability"),
        data_api_stochastic.read_table("human/initial-infections",
                                       "initial-infections"),
        data_api_stochastic.read_table("human/trials", "trials"),
        data_api_stochastic.read_table("human/start-end-date",
                                       "start-end-date"),
        data_api_stochastic.read_table("human/movement-multipliers",
                                       "movement-multipliers"),
        data_api_stochastic.read_table("human/stochastic-mode",
                                       "stochastic-mode"),
    )
    seed = loaders.readRandomSeed(
        data_api_stochastic.read_table("human/random-seed", "random-seed"))
    result, issues = np.basicSimulationInternalAgeStructure(
        network, {"S08000016": {
            "[17,70)": 10
        }}, numpy.random.default_rng(seed))

    _assert_baseline_dataframe(result)
    assert not issues
def test_readRandomSeed_bad_shape():
    with pytest.raises(AssertionError):
        loaders.readRandomSeed(pd.DataFrame())

    with pytest.raises(AssertionError):
        loaders.readRandomSeed(pd.DataFrame([0, 4, 30], columns=["Value"]))

    with pytest.raises(AssertionError):
        loaders.readRandomSeed(pd.DataFrame([0], columns=["Bad name"]))
def test_readInfectionProbability_invalid_seed():
    with pytest.raises(ValueError):
        loaders.readRandomSeed(pd.DataFrame([1.2], columns=["Value"]))

    with pytest.raises(ValueError):
        loaders.readRandomSeed(pd.DataFrame([-1], columns=["Value"]))
def test_readRandomSeed():
    df = pd.DataFrame([123], columns=["Value"])

    assert loaders.readRandomSeed(df) == 123
def createNetworkOfPopulation(
        compartment_transition_table: pd.DataFrame,
        population_table: pd.DataFrame,
        commutes_table: pd.DataFrame,
        mixing_matrix_table: pd.DataFrame,
        infectious_states: pd.DataFrame,
        infection_prob: pd.DataFrame,
        initial_infections: pd.DataFrame,
        trials: pd.DataFrame,
        movement_multipliers_table: pd.DataFrame = None,
        stochastic_mode: pd.DataFrame = None,
        random_seed: pd.DataFrame = None) -> NetworkOfPopulation:
    """Create the network of the population, loading data from files.

    :param compartment_transition_table: pd.Dataframe specifying the transition rates between infected compartments.
    :param population_table: pd.Dataframe with the population size in each region by gender and age.
    :param commutes_table: pd.Dataframe with the movements between regions.
    :param mixing_matrix_table: pd.Dataframe with the age infection matrix.
    :param movement_multipliers_table: pd.Dataframe with the movement multipliers. This may be None, in
    which case no multipliers are applied to the movements.
    :param infectious_states: States that are considered infectious
    :param infection_prob: Probability that a given contact will result in an infection
    :param initial_infections: Initial infections of the population at time 0
    :param trials: Number of trials for the model
    :param stochastic_mode: Use stochastic mode for the model
    :param random_seed: Random number generator seed used for stochastic mode
    :return: The constructed network
    """
    infection_prob = loaders.readInfectionProbability(infection_prob)

    infectious_states = loaders.readInfectiousStates(infectious_states)
    initial_infections = loaders.readInitialInfections(initial_infections)
    trials = loaders.readTrials(trials)
    stochastic_mode = loaders.readStochasticMode(stochastic_mode)
    random_seed = loaders.readRandomSeed(random_seed)

    # diseases progression matrix
    progression = loaders.readCompartmentRatesByAge(
        compartment_transition_table)

    # population census data
    population = loaders.readPopulationAgeStructured(population_table)

    # Check some requirements for this particular model to work with the progression matrix
    all_states = set()
    for states in progression.values():
        assert SUSCEPTIBLE_STATE not in states, "progression from susceptible state is not allowed"
        for state, nextStates in states.items():
            for nextState in nextStates:
                all_states.add(state)
                all_states.add(nextState)
                assert state == nextState or nextState != EXPOSED_STATE, \
                    "progression into exposed state is not allowed other than in self reference"
    assert (set(infectious_states) - all_states) == set(), \
        f"mismatched infectious states and states {infectious_states} {set(progression.keys())}"

    # people movement's graph
    graph = loaders.genGraphFromContactFile(commutes_table)

    # movement multipliers (dampening or heightening)
    if movement_multipliers_table is not None:
        movementMultipliers = loaders.readMovementMultipliers(
            movement_multipliers_table)
    else:
        movementMultipliers: Dict[int, loaders.Multiplier] = {}

    # age-based infection matrix
    mixingMatrix = loaders.MixingMatrix(mixing_matrix_table)

    agesInInfectionMatrix = set(mixingMatrix)
    for age in mixingMatrix:
        assert agesInInfectionMatrix == set(
            mixingMatrix[age]), "infection matrix columns/rows mismatch"

    # Checks across datasets
    assert agesInInfectionMatrix == set(
        progression.keys()), "infection matrix and progression ages mismatch"
    assert agesInInfectionMatrix == {age for region in population.values() for age in region}, \
        "infection matrix and population ages mismatch"
    assert set(graph.nodes()) == set(
        population.keys()), "regions mismatch between graph and population"

    state0: Dict[str, Dict[Tuple[str, str], float]] = {}
    for node in list(graph.nodes()):
        region = state0.setdefault(node, {})
        for age, compartments in progression.items():
            region[(age, SUSCEPTIBLE_STATE)] = population[node][age]
            for compartment in compartments:
                region[(age, compartment)] = 0

    logger.info("Nodes: %s, Ages: %s, States: %s", len(state0),
                agesInInfectionMatrix, all_states)
    return NetworkOfPopulation(progression=progression,
                               graph=graph,
                               initialState=state0,
                               mixingMatrix=mixingMatrix,
                               movementMultipliers=movementMultipliers,
                               infectiousStates=infectious_states,
                               infectionProb=infection_prob,
                               initialInfections=initial_infections,
                               trials=trials,
                               stochastic=stochastic_mode,
                               randomState=np.random.default_rng(random_seed))
def test_readRandomSeed_none():
    assert loaders.readRandomSeed(None) == 0
def test_readRandomSeed(seed, expected):
    df = pd.DataFrame([seed], columns=["Value"])

    assert loaders.readRandomSeed(df) == expected