def propagate_to_houses(env_dic, virus_dic, probability_home_infection_arg):
    # Houses that contain an infected and contagious person with an associated behavior weight
    # ( (1, 1.5), (1, 2), (2, 1) )
    # House 1 with 1.5 and 2 weights and House 2 with weight 1
    infected_houses_behavior = [(env_dic[IH_K][i], env_dic[IBE_K][i])
                                for i in get_contagious_people(virus_dic)]

    # We reduce_multiply_by_key multiply it to get
    # { 1: 1.5 * 2  ,   2: 1 }
    infected_houses_behavior_dic = reduce_multiply_by_key(
        infected_houses_behavior)

    # We build people at those houses with the house behavior
    # [ ([1, 2, 3], 1), ([4, 5, 6], 2), ([1, 2, 3], 2) ]
    people_in_infected_houses = [
        (env_dic[HI_K][hou], beh_p)
        for (hou, beh_p) in infected_houses_behavior_dic.items()
    ]

    # From which we designate newly infected people using weights beh_p
    infected_athome = [
        i for people, beh_p in people_in_infected_houses for i in people
        if get_r() < probability_home_infection_arg * beh_p
    ]

    # INFECTION STATE UPDATE
    update_infection_period(infected_athome, virus_dic)
def propagate_to_workplaces(env_dic, virus_dic, probability_work_infection_arg,
                            probability_remote_work_arg):
    # [1, 2, 3] go to work
    # Contagious people who will go to work
    infected_gotowork = [
        i for i in get_contagious_people(virus_dic)
        if i in env_dic[IW_K].keys() and get_r() <
        (1 - probability_remote_work_arg) * env_dic[IBE_K][i]
    ]
    # Infected workplaces
    # [ (1, 1.1), (2, 1), (1, 1.4) ]
    infected_workplaces_behavior = [(env_dic[IW_K][i], env_dic[IBE_K][i])
                                    for i in infected_gotowork]

    # Infected workplaces
    # { 1: 1.1* 1.4, 2: 1 }
    infected_workplaces_behavior_dic = reduce_multiply_by_key(
        infected_workplaces_behavior)

    # We build people at those workplaces
    # [ ([1, 2, 3], 1), ([4, 5, 6], 2), ([1, 2, 3], 2) ]
    exposed_individuals_at_work = [
        (env_dic[WI_K][k], beh_p)
        for (k, beh_p) in infected_workplaces_behavior_dic.items()
    ]

    # People who have gone to work (not isolated) and got infected
    infected_backfromwork = [
        i for people, beh_p in exposed_individuals_at_work for i in people
        if get_r() < probability_work_infection_arg * beh_p
    ]

    # INFECTION STATE UPDATE
    update_infection_period(infected_backfromwork, virus_dic)
 def test_reduce_multiply_by_key(self):
     result = reduce_multiply_by_key([(0, 2), (0, 1.5), (1, 2), ('a', 5), (99, 0), (99, 12)])
     self.assertEqual(result, {
         0: 3,
         1: 2,
         'a': 5,
         99: 0
     })
def propagate_to_stores(env_dic, virus_dic, probability_store_infection_arg,
                        same_store_preference):
    # Filter on living people because we have a random choice to make in each house
    # People who will go to their store (one person per house as imposed by lockdown)
    # [1, 2, 3, 4, 5, 6] go to the store
    individuals_gotostore = get_random_choice_list([[
        i for i in env_dic[HA_K][h]
        if (is_alive(i, virus_dic) and not (is_isolated(i, virus_dic)))
    ] for h in range(len(env_dic[HA_K]))])

    # Contagious people who will go to their store
    # [1, 4, 5] are infected and going to the store
    individuals_infected_gotostore = [
        i for i in individuals_gotostore if is_contagious(i, virus_dic)
    ]

    # [(2, 0), (3, 1), (6, 2)]  2, 3 and 6 are infected and going to the stores 0, 1 and 2
    # we divide same_store_preference by behavior since high behavior value is bad behavior
    individuals_healthy_gotostore = [
        (i,
         choose_weight_order(env_dic[HS_K][env_dic[IH_K][i]],
                             same_store_preference / env_dic[IBE_K][i]))
        for i in individuals_gotostore if not is_contagious(i, virus_dic)
    ]

    # Stores that will be visited by a contagious person
    # [ (0, 1), (0, 1.3), (2, 1.2)] where stores 0 and 2 are infected with 1, 1.3 and 1.2 weights
    infected_stores = [
        (choose_weight_order(env_dic[HS_K][env_dic[IH_K][i]],
                             same_store_preference / env_dic[IBE_K][i]),
         env_dic[IBE_K][i]) for i in individuals_infected_gotostore
    ]

    # { 0: 1*1.3, 2: 1.2 } are the weights of each infected store
    infected_stores_dic = reduce_multiply_by_key(infected_stores)

    # We get the list of people who are healty + have chosen an infected store + get bad luck with get_r
    # [2, 6] got infected
    gonna_be_infected = [
        ind for (ind, s) in individuals_healthy_gotostore
        if s in infected_stores_dic.keys()
        and get_r() < probability_store_infection_arg * env_dic[IBE_K][ind] *
        infected_stores_dic[s]
    ]

    # INFECTION STATE UPDATE
    update_infection_period(gonna_be_infected, virus_dic)