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 |
| BreastfeedingNet | Network for breastfeeding transmission |
| ClusterNet | Fully connected clusters of agents, e.g. households, schools, or workplaces |
| DynamicNetwork | A network where partnerships update dynamically |
| HybridNet | Covasim v3’s “hybrid” population: households, schools, workplaces, and community |
| MFNet | This network is built by randomly pairing males and female with variable |
| MSMNet | A network that randomly pairs males |
| MaternalNet | Alias for PrenatalNet, kept for backwards compatibility |
| 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 | Network to track postnatal processes |
| PrenatalNet | Prenatal transmission network |
| RandomExactNet | Random connectivity between agents |
| RandomNet | A faster, approximate version of ss.RandomExactNet |
| 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
networks.AgeGroup(low, high, do_cache=True)A simple age-based filter that returns uids of agents that match the criteria
BreastfeedingNet
networks.BreastfeedingNet(pars=None, **kwargs)Network for breastfeeding transmission
To model breastfeeding transmission, include this network in a Sim that contains a Pregnancy module. Edges will be automatically added and removed from this network tracking the breastfeeding status from the Pregnancy module.
Methods
| Name | Description |
|---|---|
| add_pairs | Add pairs upon delivery if the mother is breastfeeding the newborn - called via Pregnancy.process_delivery() |
| end_pairs | Remove edges for mothers whose breastfeeding status has changed in the Pregnancy module |
add_pairs
networks.BreastfeedingNet.add_pairs(mother_uids=None, newborn_uids=None)Add pairs upon delivery if the mother is breastfeeding the newborn - called via Pregnancy.process_delivery()
end_pairs
networks.BreastfeedingNet.end_pairs()Remove edges for mothers whose breastfeeding status has changed in the Pregnancy module
ClusterNet
networks.ClusterNet(
pars=None,
cluster_size=_,
age_range=_,
beta=_,
dynamic=_,
**kwargs,
)Fully connected clusters of agents, e.g. households, schools, or workplaces
Each agent (optionally, only those within an age range) is assigned to one cluster, with cluster sizes drawn from cluster_size, and every pair of agents within a cluster is connected. Agents are assigned to clusters in a random order (from a CRN-safe random number per agent), so clusters are not correlated with other networks. Based on make_microstructured_contacts() from Covasim v3: as there, clusters of size 0 are skipped, and the last cluster is truncated to fit.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| cluster_size | int/ss.Dist |
the size of each cluster; a number is the mean of a Poisson distribution | _ |
| age_range | list | if supplied, only agents with age_range[0] <= age < age_range[1] are included |
_ |
| beta | float | the beta value for each edge | _ |
| dynamic | bool | if True, the clusters are recreated on each timestep; if False (default), they are created once and never change | _ |
Example
households = ss.ClusterNet(name='households', cluster_size=ss.poisson(3))
sim = ss.Sim(diseases='sis', networks=households)
sim.run()Methods
| Name | Description |
|---|---|
| add_pairs | Assign agents to clusters, and connect every pair of agents within each cluster |
| step | If dynamic, recreate the clusters; otherwise, do nothing |
add_pairs
networks.ClusterNet.add_pairs()Assign agents to clusters, and connect every pair of agents within each cluster
step
networks.ClusterNet.step()If dynamic, recreate the clusters; otherwise, do nothing
DynamicNetwork
networks.DynamicNetwork(pars=None, edges=None, **kwargs)A network where partnerships update dynamically
Methods
| Name | Description |
|---|---|
| end_pairs | Remove partnerships whose duration has expired or whose members have died. |
| step | Remove expired partnerships and add new ones |
end_pairs
networks.DynamicNetwork.end_pairs()Remove partnerships whose duration has expired or whose members have died.
step
networks.DynamicNetwork.step()Remove expired partnerships and add new ones
HybridNet
networks.HybridNet(
pars=None,
household_size=_,
contacts=_,
beta=_,
school_ages=_,
work_ages=_,
dynamic=_,
uniform_targets=_,
**kwargs,
)Covasim v3’s “hybrid” population: households, schools, workplaces, and community
When added to a sim, this expands into four separate networks: households (h, an ss.ClusterNet), and schools (s), workplaces (w), and community (c), each an ss.RandomNet with Poisson-distributed contacts. As in Covasim v3, the networks are static, and schools and workplaces are random networks restricted by age. Each network can then be modified separately, e.g. sim.networks.s.
The default beta values are Covasim v3’s per-layer relative transmissibility, and are applied to the edges of each network; for per-network transmissibility on the disease instead, set them to 1 and use e.g. ss.SIS(beta=dict(h=0.3, s=0.06, w=0.06, c=0.03)).
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| household_size | int/ss.Dist |
the size of each household; a number is the mean of a Poisson distribution | _ |
| contacts | dict | the mean number of contacts per agent in schools, workplaces, and community (numbers or ss.Dists) |
_ |
| beta | dict | the beta value for each edge in each network | _ |
| school_ages | list | the age range of agents in schools | _ |
| work_ages | list | the age range of agents in workplaces | _ |
| dynamic | bool | whether the networks are recreated on each timestep | _ |
| uniform_targets | bool | whether to choose the targets of edges in schools, workplaces, and community uniformly, as in Covasim v3 (see ss.RandomNet) |
_ |
Examples
sim = ss.Sim(diseases='sis', networks=ss.HybridNet())
sim.run()
print(sim.networks.keys()) # ['h', 's', 'w', 'c']
# Larger households and smaller schools; contacts and beta can be partial
hybrid = ss.HybridNet(household_size=ss.poisson(3), contacts=dict(s=10))Methods
| Name | Description |
|---|---|
| expand | Create the four networks; called automatically when added to a sim |
| step | Not used, since the networks returned by expand() are used instead |
expand
networks.HybridNet.expand()Create the four networks; called automatically when added to a sim
step
networks.HybridNet.step()Not used, since the networks returned by expand() are used instead
MFNet
networks.MFNet(
pars=None,
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, i.e. a multiplier (from 0 to 1) on the probability of participating | _ |
Methods
| Name | Description |
|---|---|
| add_pairs | Form new sexual partnerships between available male and female agents |
| 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 |
add_pairs
networks.MFNet.add_pairs()Form new sexual partnerships between available male and female agents
set_debut
networks.MFNet.set_debut(upper_age=None)Set debut age
set_network_states
networks.MFNet.set_network_states(upper_age=None)Set network states including age of entry into network and participation rates
set_participation
networks.MFNet.set_participation(upper_age=None)Set people who will participate in the network at some point
MSMNet
networks.MSMNet(
pars=None,
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
networks.MSMNet.set_network_states(upper_age=None)Set network states including age of entry into network and participation rates
MaternalNet
networks.MaternalNet(pars=None, edges=None, **kwargs)Alias for PrenatalNet, kept for backwards compatibility
MixingPool
networks.MixingPool(
pars=None,
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 | _ |
Examples
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 = 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(
pars=None,
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) | _ |
Examples
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]], # Illustrative contact matrix
)
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 |
| shrink | Shrink the size of the mixing pools for saving to disk |
| 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
shrink
networks.MixingPools.shrink()Shrink the size of the mixing pools for saving to disk
validate_pars
networks.MixingPools.validate_pars()Check that src and dst have correct types, and contacts is the correct shape
Network
networks.Network(pars=None, edges=None, **kwargs)A class holding a single network of contact edges (connections) between people as well as methods for updating these. Networks mediate disease transmission between agents in ss.People; see ss.Disease for how transmission uses network edges, and ss.RandomNet, ss.MFNet, ss.PrenatalNet for built-in network types.
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 |
|---|---|---|---|
| pars | dict | parameters, for subclasses that define them | None |
| edges | dict / dataframe |
the edges of the network, as an alternative to passing them as keyword arguments | None |
| 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 |
| kwargs | dict | standard module arguments (e.g. name, label, dt) are passed to update_pars(); other keys are copied directly into the network as edges |
{} |
Note that all edge arguments 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(edges=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(edges=network.edges, 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. |
| eligible | Return the agents who can form edges: alive, born, and (optionally) within an age range |
| find_contacts | Find all contacts of the specified people |
| from_df | Set the edges from a dataframe or a dict of arrays |
| 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_edges | Remove the specified edges from the network |
| 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
networks.Network.append(edges=None, **kwargs)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 |
eligible
networks.Network.eligible(age_range=None)Return the agents who can form edges: alive, born, and (optionally) within an age range
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| age_range | list | if supplied, only include agents with age_range[0] <= age < age_range[1] |
None |
find_contacts
networks.Network.find_contacts(inds, as_array=True)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. Each contact is only returned once (otherwise if the Network has explicit symmetric interactions, they could appear multiple times), so 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 / set | the indices of the 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
networks.Network.from_df(df, keys=None)Set the edges from a dataframe or a dict of arrays
Replaces the existing edges, and returns the network, so it can also be used to create a new network. If beta is not supplied, it defaults to 1.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| df | dataframe / dict |
the edges, with columns p1, p2, and (optionally) beta |
required |
| keys | list | the columns to use (default: the network’s meta keys) | None |
Examples
net = ss.Network(name='mynet').from_df(dict(p1=[0,1,2], p2=[1,2,3])) # Create a new network
net.from_df(df) # Replace the edges of an existing networkget_inds
networks.Network.get_inds(inds, remove=False)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
networks.Network.net_beta(disease_beta=None, inds=None, disease=None)Calculate the beta for the given disease and network
plot
networks.Network.plot(max_edges=500, random=False, alpha=0.2, **kwargs)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 | figure and style arguments (e.g. figsize, font) are passed to ss.plot_args(), the rest 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_edges
networks.Network.remove_edges(inds)Remove the specified edges from the network
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| inds | array | the indices of the edges to remove, or a boolean mask the same length as the network | required |
Example
net = sim.networks.randomnet
net.remove_edges(net.edges.p1 == 0) # Remove all edges with agent 0 as p1remove_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
networks.Network.to_graph(max_edges=None, random=False)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 |
Examples
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
networks.Network.validate(force=True)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
networks.PostnatalNet(pars=None, dur=None, **kwargs)Network to track postnatal processes
This network automatically has edges added between mothers and infants upon birth if a Pregnancy module is present in the simulation. The edges persist until the specified duration has elapsed, at which point they are automatically removed. This allows different PostnatalNet instances have different postnatal periods specific to what is being modelled. Transmission along this network is possible if a beta value >0 is specified. Otherwise, transmission will be skipped.
By default, the postnatal duration is based on the maternal UID and would be the same for all infants of that mother, although derived classes could modify this behavior.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| pars | dict | passed to ss.DynamicNetwork |
None |
| dur | ss.dur / ss.Dist |
edge duration (postpartum period); if None, edges persist until agents die | None |
| **kwargs | dict | merged with pars |
{} |
PrenatalNet
networks.PrenatalNet(pars=None, edges=None, **kwargs)Prenatal transmission network
Although edges change over time, the edges are managed via ss.Pregnancy as pregnancies start and finish. The prenatal network therefore is not derived from DynamicNetwork as it does not manage its own updates.
RandomExactNet
networks.RandomExactNet(
pars=None,
n_contacts=_,
dur=_,
beta=_,
age_range=_,
dynamic=_,
**kwargs,
)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 | _ |
| age_range | list | if supplied, only agents with age_range[0] <= age < age_range[1] are included |
_ |
| dynamic | bool | if True (default), edges are replaced once their duration ends; if False, edges are created once and never change (so agents who join later, e.g. newborns, are not added) | _ |
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.
Example
# Static network with Poisson-distributed contacts among adults, as in Covasim v3
net = ss.RandomNet(n_contacts=ss.poisson(20), age_range=[18, 65], dynamic=False)Methods
| Name | Description |
|---|---|
| add_pairs | Generate edges |
| get_edges | Efficiently find edges |
| step | If dynamic, replace expired edges; otherwise, do nothing |
add_pairs
networks.RandomExactNet.add_pairs()Generate edges
get_edges
networks.RandomExactNet.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 |
step
networks.RandomExactNet.step()If dynamic, replace expired edges; otherwise, do nothing
RandomNet
networks.RandomNet(
pars=None,
n_contacts=_,
dur=_,
beta=_,
age_range=_,
dynamic=_,
uniform_targets=_,
**kwargs,
)A faster, approximate version of ss.RandomExactNet
Identical to ss.RandomExactNet except that the target end of each edge is drawn by sampling the source stubs with replacement, rather than by shuffling them (i.e. sampling without replacement). This is roughly 1.8x faster at generating edges, but the per-agent degree is no longer fixed: the source side of each edge is still exactly n_contacts, while the target side is Poisson-distributed with mean n_contacts. Agents therefore have somewhat more variable numbers of contacts than with ss.RandomExactNet.
Because targets are drawn from the stub list, an agent’s chance of being picked as a target is proportional to its own n_contacts, exactly as in ss.RandomExactNet. This means the approximation preserves the mixing structure of risk-stratified networks (e.g. a small high-risk core with many contacts correctly forms most of its edges with itself); drawing targets uniformly over agents instead would destroy that clustering and bias the realized degrees.
Alternatively, with uniform_targets=True, each target is chosen uniformly from all eligible agents, regardless of their own n_contacts, as in Covasim v3’s random networks. This gives less variable numbers of contacts (e.g. with n_contacts=ss.poisson(20), a variance of about 15, rather than 30 for the default or 20 for ss.RandomExactNet), but loses the mixing structure described above.
Note: like ss.RandomExactNet, this is not random-number safe; see ss.RandomSafeNet for the CRN-safe (but slower) version.
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 | _ |
| age_range | list | if supplied, only agents with age_range[0] <= age < age_range[1] are included |
_ |
| dynamic | bool | if True (default), edges are replaced once their duration ends; if False, edges are created once and never change | _ |
| uniform_targets | bool | if True, choose the target of each edge uniformly from the eligible agents, rather than in proportion to their number of contacts | _ |
Example
# Static network with Poisson-distributed contacts, as in Covasim v3
net = ss.RandomNet(n_contacts=ss.poisson(20), dynamic=False, uniform_targets=True)Methods
| Name | Description |
|---|---|
| get_edges | Find edges by sampling the source stubs with replacement (see ss.RandomExactNet.get_edges) |
get_edges
networks.RandomNet.get_edges(inds, n_contacts)Find edges by sampling the source stubs with replacement (see ss.RandomExactNet.get_edges)
RandomSafeNet
networks.RandomSafeNet(pars=None, n_edges=_, dur=_, beta=_, **kwargs)Create a CRN-safe, O(N) random network
This network is similar to ss.RandomExactNet(), 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.RandomExactNet(), so should be used where CRN safety is important (e.g., scenario analysis).
Note: ss.RandomExactNet uses n_contacts, which is the total number of contacts per agent. ss.RandomSafeNet uses n_edges, which is the total number of edges per agent. Since contacts are usually bidirectional, n_contacts = 2*n_edges. For example, ss.RandomExactNet(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
networks.RandomSafeNet.form_pairs(debug=False)From a 2N input array, return 2N-2 nearest-neighbor pairs
plot_matrix
networks.RandomSafeNet.plot_matrix(**kwargs)Plot the distance matrix used for forming pairs: only ±1 from the diagonal is used
rep_rand
networks.RandomSafeNet.rep_rand(uids, sort=True)Reproducible repeated random numbers
Route
networks.Route(name=None, label=None, **kwargs)A transmission route – e.g., a network, mixing pool, environmental transmission, etc.
Methods
| Name | Description |
|---|---|
| compute_transmission | Compute transmission probabilities along this route (must be overridden by subclasses). |
compute_transmission
networks.Route.compute_transmission(
rel_sus,
rel_trans,
disease_beta,
disease=None,
)Compute transmission probabilities along this route (must be overridden by subclasses).
SexualNetwork
networks.SexualNetwork(pars=None, edges=None, **kwargs)Base class for all sexual networks
Methods
| Name | Description |
|---|---|
| active | Return boolean array of agents who are alive, participating, and past sexual debut. |
| available | Return UIDs of active agents of the given sex who are not currently partnered. |
| net_beta | Compute per-edge transmission probability accounting for number of sex acts. |
active
networks.SexualNetwork.active(people)Return boolean array of agents who are alive, participating, and past sexual debut.
available
networks.SexualNetwork.available(people, sex)Return UIDs of active agents of the given sex who are not currently partnered.
net_beta
networks.SexualNetwork.net_beta(disease_beta=None, inds=None, disease=None)Compute per-edge transmission probability accounting for number of sex acts.
StaticNet
networks.StaticNet(graph=None, pars=None, **kwargs)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)Functions
| Name | Description |
|---|---|
| fisher_yates_shuffle | In-place Fisher-Yates shuffle using precomputed uniform random values. |
fisher_yates_shuffle
networks.fisher_yates_shuffle(arr, randvals)In-place Fisher-Yates shuffle using precomputed uniform random values.
Equivalent to np.random.permutation (a uniform random shuffle), but ~1.3x faster for the large arrays used in network generation. randvals should be uniform on [0, 1) and the same length as arr.
Note: randvals is consumed in order (randvals[k] for the k-th swap), not indexed by position. This means that changing the array length (e.g. adding one agent) shifts every swap, so the shuffle is not random-number safe – matching ss.RandomExactNet’s intended behavior (see ss.RandomSafeNet for the CRN-safe version).