networks
networks
Networks that connect people within a population
Classes
Name | Description |
---|---|
AgeGroup | A simple age-based filter that returns uids of agents that match the criteria |
DynamicNetwork | A network where partnerships update dynamically |
MFNet | This network is built by randomly pairing males and female with variable |
MSMNet | A network that randomly pairs males |
MaternalNet | Base class for maternal transmission |
MixingPool | Define a single mixing pool; can be used as a drop-in replacement for a network. |
MixingPools | A container for creating a rectangular array of MixingPool instances |
Network | A class holding a single network of contact edges (connections) between people |
PostnatalNet | Postnatal transmission network |
PrenatalNet | Prenatal transmission network |
RandomNet | Random connectivity between agents |
RandomSafeNet | Create a CRN-safe, O(N) random network |
Route | A transmission route – e.g., a network, mixing pool, environmental transmission, etc. |
SexualNetwork | Base class for all sexual networks |
StaticNet | A network class of static partnerships converted from a networkx graph. There’s no formation of new partnerships |
AgeGroup
self, low, high, do_cache=True) networks.AgeGroup(
A simple age-based filter that returns uids of agents that match the criteria
DynamicNetwork
self, **kwargs) networks.DynamicNetwork(
A network where partnerships update dynamically
MFNet
networks.MFNet(self,
=None,
pars=_,
duration=_,
debut=_,
acts=_,
participation=_,
rel_part_rates**kwargs,
)
This network is built by randomly pairing males and female with variable relationship durations.
Parameters
Name | Type | Description | Default |
---|---|---|---|
duration | ss.Dist |
Can vary by age, year, and individual pair. Set scale=exp(mu) and s=sigma where mu,sigma are of the underlying normal distribution. | _ |
debut | ss.Dist |
Age of debut can vary by using callable parameter values | _ |
acts | ss.Dist |
Number of acts per year | _ |
participation | ss.Dist |
Probability of participating in this network - can vary by individual properties (age, sex, …) using callable parameter values | _ |
rel_part_rates | float | Relative participation in the network | _ |
Methods
Name | Description |
---|---|
set_debut | Set debut age |
set_network_states | Set network states including age of entry into network and participation rates |
set_participation | Set people who will participate in the network at some point |
set_debut
=None) networks.MFNet.set_debut(upper_age
Set debut age
set_network_states
=None) networks.MFNet.set_network_states(upper_age
Set network states including age of entry into network and participation rates
set_participation
=None) networks.MFNet.set_participation(upper_age
Set people who will participate in the network at some point
MSMNet
networks.MSMNet(self,
=None,
pars=_,
duration=_,
debut=_,
acts=_,
participation**kwargs,
)
A network that randomly pairs males
Parameters
Name | Type | Description | Default |
---|---|---|---|
duration | ss.Dist |
Can vary by age, year, and individual pair. Set scale=exp(mu) and s=sigma where mu,sigma are of the underlying normal distribution. | _ |
debut | ss.Dist |
Age of debut can vary by using callable parameter values | _ |
acts | ss.Dist |
Number of acts per year | _ |
participation | ss.Dist |
Probability of participating in this network - can vary by individual properties (age, sex, …) using callable parameter values | _ |
Methods
Name | Description |
---|---|
add_pairs | Pair all unpartnered MSM |
set_network_states | Set network states including age of entry into network and participation rates |
add_pairs
networks.MSMNet.add_pairs()
Pair all unpartnered MSM
set_network_states
=None) networks.MSMNet.set_network_states(upper_age
Set network states including age of entry into network and participation rates
MaternalNet
self, **kwargs) networks.MaternalNet(
Base class for maternal transmission Use PrenatalNet and PostnatalNet to capture transmission in different phases
Methods
Name | Description |
---|---|
add_pairs | Add connections between pregnant women and their as-yet-unborn babies |
step | Set beta to 0 for women who complete duration of transmission |
add_pairs
networks.MaternalNet.add_pairs(=None,
mother_inds=None,
unborn_inds=None,
dur=None,
start )
Add connections between pregnant women and their as-yet-unborn babies
step
networks.MaternalNet.step()
Set beta to 0 for women who complete duration of transmission Keep connections for now, might want to consider removing
NB: add_pairs() and end_pairs() are NOT called here; this is done separately in ss.Pregnancy.update_states().
MixingPool
networks.MixingPool(self,
=None,
pars=_,
diseases=_,
src=_,
dst=_,
beta=_,
n_contacts**kwargs,
)
Define a single mixing pool; can be used as a drop-in replacement for a network.
Parameters
Name | Type | Description | Default |
---|---|---|---|
diseases | str | the diseases that transmit via this mixing pool | _ |
src | inds |
source agents; can be AgeGroup(), ss.uids(), or lambda(sim); None indicates all alive agents | _ |
dst | inds |
destination agents; as above | _ |
beta | float | overall transmission (note: use a float, not a TimePar; the time component is usually handled by the disease beta) | _ |
n_contacts | Dist | the number of effective contacts of the destination agents | _ |
Example:
import starsim as ss
# Set the parameters
mp_pars = dict(
src = lambda sim: sim.people.male, # only males are infectious
dst = None, # all agents are susceptible
beta = ss.Rate(0.2),
n_contacts = ss.poisson(lam=4),
)
# Seed 5% of the male population
def p_init(self, sim, uids):
return 0.05*sim.people.male
# Create and run the sim
sis = ss.SIS(init_prev=p_init)
mp = ss.MixingPool(**mp_pars)
sim = ss.Sim(diseases=sis, networks=mp)
sim.run()
sim.plot()
Methods
Name | Description |
---|---|
compute_transmission | Calculate transmission |
remove_uids | If UIDs are supplied explicitly, remove them if people die |
shrink | Shrink the size of the mixing pool for saving to disk |
step | Update source and target UIDs |
compute_transmission
networks.MixingPool.compute_transmission(
rel_sus,
rel_trans,
disease_beta,
disease, )
Calculate transmission
This is called from Infection.infect() together with network transmission.
Parameters
Name | Type | Description | Default |
---|---|---|---|
rel_sus | float | Relative susceptibility | required |
rel_trans | float | Relative infectiousness | required |
disease_beta | float | The beta value for the disease | required |
Returns: UIDs of agents who acquired the disease at this step
remove_uids
networks.MixingPool.remove_uids(uids)
If UIDs are supplied explicitly, remove them if people die
shrink
networks.MixingPool.shrink()
Shrink the size of the mixing pool for saving to disk
step
networks.MixingPool.step()
Update source and target UIDs
MixingPools
networks.MixingPools(self,
=None,
pars=_,
diseases=_,
src=_,
dst=_,
beta=_,
n_contacts**kwargs,
)
A container for creating a rectangular array of MixingPool instances
By default, separates the population into <15 and >15 age groups.
Parameters
Name | Type | Description | Default |
---|---|---|---|
diseases | str | the diseases that transmit via these mixing pools | _ |
src | inds |
source agents; can be AgeGroup(), ss.uids(), or lambda(sim); None indicates all alive agents | _ |
dst | inds |
destination agents; as above | _ |
beta | float | overall transmission via these mixing pools | _ |
n_contacts | array | the relative connectivity between different mixing pools (can be float or Dist) | _ |
Example:
import starsim as ss
mps = ss.MixingPools(
diseases = 'sis',
beta = 0.1,
src = {'0-15': ss.AgeGroup(0, 15), '15+': ss.AgeGroup(15, None)},
dst = {'0-15': ss.AgeGroup(0, 15), '15+': ss.AgeGroup(15, None)},
n_contacts = [[2.4, 0.49], [0.91, 0.16]],
)
sim = ss.Sim(diseases='sis', networks=mps).run()
sim.plot()
Methods
Name | Description |
---|---|
init_post | Initialize each mixing pool |
remove_uids | Remove UIDs from each mixing pool |
validate_pars | Check that src and dst have correct types, and contacts is the correct shape |
init_post
networks.MixingPools.init_post()
Initialize each mixing pool
remove_uids
networks.MixingPools.remove_uids(uids)
Remove UIDs from each mixing pool
validate_pars
networks.MixingPools.validate_pars()
Check that src and dst have correct types, and contacts is the correct shape
Network
self, name=None, label=None, **kwargs) networks.Network(
A class holding a single network of contact edges (connections) between people as well as methods for updating these.
The input is typically arrays including: person 1 of the connection, person 2 of the connection, the weight of the connection, the duration and start/end times of the connection.
Parameters
Name | Type | Description | Default |
---|---|---|---|
p1 | array | an array of length N, the number of connections in the network, with the indices of people on one side of the connection. | required |
p2 | array | an array of length N, the number of connections in the network, with the indices of people on the other side of the connection. | required |
beta | array | an array representing relative transmissibility of each connection for this network - TODO, do we need this? | required |
label | str | the name of the network (optional) | None |
kwargs | dict | other keys copied directly into the network | {} |
Note that all arguments (except for label) must be arrays of the same length, although not all have to be supplied at the time of creation (they must all be the same at the time of initialization, though, or else validation will fail).
Examples:
# Generate an average of 10 contacts for 1000 people
n_contacts_pp = 10
n_people = 1000
n = n_contacts_pp * n_people
p1 = np.random.randint(n_people, size=n)
p2 = np.random.randint(n_people, size=n)
beta = np.ones(n)
network = ss.Network(p1=p1, p2=p2, beta=beta, label='rand')
network = ss.Network(dict(p1=p1, p2=p2, beta=beta), label='rand') # Alternate method
# Convert one network to another with extra columns
index = np.arange(n)
self_conn = p1 == p2
network2 = ss.Network(**network, index=index, self_conn=self_conn, label=network.label)
Attributes
Name | Description |
---|---|
beta | Relative transmission on each network edge |
members | Return sorted array of all members |
p1 | The first half of a network edge (person 1) |
p2 | The second half of a network edge (person 2) |
Methods
Name | Description |
---|---|
add_pairs | Define how pairs of people are formed |
append | Append edges to the current network. |
find_contacts | Find all contacts of the specified people |
from_df | Convert from a dataframe |
get_inds | Get the specified indices from the edgelist and return them as a dict. |
init_pre | Initialize with the sim, initialize the edges, and validate p1 and p2 |
init_results | Store network length by default |
meta_keys | Return the keys for the network’s meta information |
net_beta | Calculate the beta for the given disease and network |
plot | Plot the network using NetworkX. |
pop_inds | “Pop” the specified indices from the edgelist and return them as a dict. |
remove_uids | Remove interactions involving specified UIDs |
set_network_states | Many network states depend on properties of people – e.g. MSM depends on being male, |
shrink | Shrink the size of the network for saving to disk |
to_df | Convert to dataframe |
to_dict | Convert to dictionary |
to_edgelist | Convert the network to a list of edges (paired nodes) |
to_graph | Convert to a networkx DiGraph |
update_results | Store the number of edges in the network |
validate | Check the integrity of the network: right types, right lengths. |
validate_uids | Ensure that p1, p2 are both UID arrays |
add_pairs
networks.Network.add_pairs()
Define how pairs of people are formed
append
=None, **kwargs) networks.Network.append(edges
Append edges to the current network.
Parameters
Name | Type | Description | Default |
---|---|---|---|
edges | dict | a dictionary of arrays with keys p1,p2,beta, as returned from network.pop_inds() | None |
find_contacts
=True) networks.Network.find_contacts(inds, as_array
Find all contacts of the specified people
For some purposes (e.g. contact tracing) it’s necessary to find all the edges associated with a subset of the people in this network. Since edges are bidirectional it’s necessary to check both p1 and p2 for the target indices. The return type is a Set so that there is no duplication of indices (otherwise if the Network has explicit symmetric interactions, they could appear multiple times). This is also for performance so that the calling code doesn’t need to perform its own unique() operation. Note that this cannot be used for cases where multiple connections count differently than a single infection, e.g. exposure risk.
Parameters
Name | Type | Description | Default |
---|---|---|---|
inds | array | indices of people whose edges to return | required |
as_array | bool | if true, return as sorted array (otherwise, return as unsorted set) | True |
Returns
Name | Type | Description |
---|---|---|
contact_inds | array | a set of indices for pairing partners |
Example: If there were a network with - p1 = [1,2,3,4] - p2 = [2,3,1,4] Then find_edges([1,3]) would return {1,2,3}
from_df
=None) networks.Network.from_df(df, keys
Convert from a dataframe
get_inds
=False) networks.Network.get_inds(inds, remove
Get the specified indices from the edgelist and return them as a dict.
Parameters
Name | Type | Description | Default |
---|---|---|---|
inds | (int, array, slice) | the indices to find | required |
remove | bool | whether to remove the indices | False |
init_pre
networks.Network.init_pre(sim)
Initialize with the sim, initialize the edges, and validate p1 and p2
init_results
networks.Network.init_results()
Store network length by default
meta_keys
networks.Network.meta_keys()
Return the keys for the network’s meta information
net_beta
=None, inds=None, disease=None) networks.Network.net_beta(disease_beta
Calculate the beta for the given disease and network
plot
=500, random=False, alpha=0.2, **kwargs) networks.Network.plot(max_edges
Plot the network using NetworkX.
Parameters
Name | Type | Description | Default |
---|---|---|---|
max_edges | int | the maximum number of edges to show | 500 |
random | bool | if true, select edges randomly; otherwise, show the first N | False |
alpha | float | the alpha value of the edges | 0.2 |
kwargs | dict | passed to nx.draw_networkx() | {} |
pop_inds
networks.Network.pop_inds(inds)
“Pop” the specified indices from the edgelist and return them as a dict. Returns arguments in the right format to be used with network.append().
Parameters
Name | Type | Description | Default |
---|---|---|---|
inds | (int, array, slice) | the indices to be removed | required |
remove_uids
networks.Network.remove_uids(uids)
Remove interactions involving specified UIDs This method is typically called via People.remove()
and is specifically used when removing agents from the simulation.
set_network_states
networks.Network.set_network_states(people)
Many network states depend on properties of people – e.g. MSM depends on being male, age of debut varies by sex and over time, and participation rates vary by age. Each time states are dynamically grown, this function should be called to set the network states that depend on other states.
shrink
networks.Network.shrink()
Shrink the size of the network for saving to disk
to_df
networks.Network.to_df()
Convert to dataframe
to_dict
networks.Network.to_dict()
Convert to dictionary
to_edgelist
networks.Network.to_edgelist()
Convert the network to a list of edges (paired nodes)
to_graph
=None, random=False) networks.Network.to_graph(max_edges
Convert to a networkx DiGraph
Parameters
Name | Type | Description | Default |
---|---|---|---|
max_edges | int | the maximum number of edges to show | None |
random | bool | if true, select edges randomly; otherwise, show the first N | False |
Example:
import networkx as nx
sim = ss.Sim(n_agents=100, networks='mf').init()
G = sim.networks.randomnet.to_graph()
nx.draw(G)
update_results
networks.Network.update_results()
Store the number of edges in the network
validate
=True) networks.Network.validate(force
Check the integrity of the network: right types, right lengths.
If dtype is incorrect, try to convert automatically; if length is incorrect, do not.
validate_uids
networks.Network.validate_uids()
Ensure that p1, p2 are both UID arrays
PostnatalNet
self, **kwargs) networks.PostnatalNet(
Postnatal transmission network
PrenatalNet
self, **kwargs) networks.PrenatalNet(
Prenatal transmission network
RandomNet
self, pars=None, n_contacts=_, dur=_, beta=_, **kwargs) networks.RandomNet(
Random connectivity between agents
Parameters
Name | Type | Description | Default |
---|---|---|---|
n_contacts | int/ss.Dist |
the average number of (bidirectional) contacts between agents | _ |
dur | int/ss.dur |
the duration of each contact | _ |
beta | float | the default beta value for each edge | _ |
Note: n_contacts = 10 will create 5 edges per agent. Since disease transmission usually occurs bidirectionally, this means that the effective number of contacts per agent is actually 10. Consider 3 agents with 3 edges between them (a triangle): each agent is connected to 2 other agents.
Methods
Name | Description |
---|---|
add_pairs | Generate edges |
get_edges | Efficiently find edges |
get_source | Optimized helper function for getting contacts |
add_pairs
networks.RandomNet.add_pairs()
Generate edges
get_edges
networks.RandomNet.get_edges(inds, n_contacts)
Efficiently find edges
Note that because of the shuffling operation, each person is assigned 2N contacts (i.e. if a person has 5 contacts, they appear 5 times in the ‘source’ array and 5 times in the ‘target’ array). Therefore, the n_contacts
argument to this function should be HALF of the total contacts a person is expected to have, if both the source and target array outputs are used (e.g. for social contacts)
adjusted_number_of_contacts = np.round(n_contacts / 2).astype(ss.dtype.int)
Whereas for asymmetric contacts (e.g. staff-public interactions) it might not be necessary
Parameters
Name | Type | Description | Default |
---|---|---|---|
inds | list / array | person indices | required |
n_contacts | list / array | the same length as inds with the number of bidirectional contacts to assign to each person |
required |
Returns
Name | Type | Description |
---|---|---|
Two arrays, for source and target |
get_source
networks.RandomNet.get_source(inds, n_contacts)
Optimized helper function for getting contacts
RandomSafeNet
self, pars=None, n_edges=_, dur=_, beta=_, **kwargs) networks.RandomSafeNet(
Create a CRN-safe, O(N) random network
This network is similar to ss.RandomNet()
, but is random-number safe (i.e., the addition of a single new agent will not perturb the entire rest of the network). However, it is somewhat slower than ss.RandomNet()
, so should be used where CRN safety is important (e.g., scenario analysis).
Note: ss.RandomNet
uses n_contacts
, which is the total number of contacts per agent. ss.RandomSateNet
users n_edges
, which is the total number of edges per agent. Since contacts are usually bidirectional, n_contacts = 2*n_edges. For example, ss.RandomNet(n_contacts=10)
will give (nearly) identical results to ss.RandomSafeNet(n_edges=5)
. In addition, whereas n_contacts
can be a distribution, n_edges
can only be an integer.
Parameters
Name | Type | Description | Default |
---|---|---|---|
n_edges | int | the average number of (bi-directional) edges between agents | _ |
dur | int/ss.dur |
the duration of each contact | _ |
beta | float | the default beta value for each edge | _ |
Methods
Name | Description |
---|---|
add_pairs | Generate edges |
form_pairs | From a 2N input array, return 2N-2 nearest-neighbor pairs |
plot_matrix | Plot the distance matrix used for forming pairs: only ±1 from the diagonal is used |
rep_rand | Reproducible repeated random numbers |
add_pairs
networks.RandomSafeNet.add_pairs()
Generate edges
form_pairs
=False) networks.RandomSafeNet.form_pairs(debug
From a 2N input array, return 2N-2 nearest-neighbor pairs
plot_matrix
**kwargs) networks.RandomSafeNet.plot_matrix(
Plot the distance matrix used for forming pairs: only ±1 from the diagonal is used
rep_rand
=True) networks.RandomSafeNet.rep_rand(uids, sort
Reproducible repeated random numbers
Route
self, name=None, label=None, **kwargs) networks.Route(
A transmission route – e.g., a network, mixing pool, environmental transmission, etc.
SexualNetwork
self, **kwargs) networks.SexualNetwork(
Base class for all sexual networks
StaticNet
self, graph=None, pars=None, **kwargs) networks.StaticNet(
A network class of static partnerships converted from a networkx graph. There’s no formation of new partnerships and initialized partnerships only end when one of the partners dies. The networkx graph can be created outside Starsim if population size is known. Or the graph can be created by passing a networkx generator function to Starsim.
If “seed=True” is passed as a keyword argument or a parameter in pars, it is replaced with the built-in RNG. The parameter “n” is supplied automatically to be equal to n_agents.
Examples:
# Generate a networkx graph and pass to Starsim
import networkx as nx
import starsim as ss
g = nx.scale_free_graph(n=10000)
ss.StaticNet(graph=g)
# Pass a networkx graph generator to Starsim
ss.StaticNet(graph=nx.erdos_renyi_graph, p=0.0001, seed=True)