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

networks.AgeGroup(self, low, high, do_cache=True)

A simple age-based filter that returns uids of agents that match the criteria

DynamicNetwork

networks.DynamicNetwork(self, **kwargs)

A network where partnerships update dynamically

MFNet

networks.MFNet(
    self,
    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 _

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
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(
    self,
    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(self, **kwargs)

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(
    mother_inds=None,
    unborn_inds=None,
    dur=None,
    start=None,
)

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,
    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 _

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,
    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) _

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

networks.Network(self, name=None, label=None, **kwargs)

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
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
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. 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
networks.Network.from_df(df, keys=None)

Convert from a dataframe

get_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 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
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

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
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(self, **kwargs)

Postnatal transmission network

PrenatalNet

networks.PrenatalNet(self, **kwargs)

Prenatal transmission network

RandomNet

networks.RandomNet(self, pars=None, n_contacts=_, dur=_, beta=_, **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 _

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

networks.RandomSafeNet(self, pars=None, n_edges=_, dur=_, beta=_, **kwargs)

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
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(self, name=None, label=None, **kwargs)

A transmission route – e.g., a network, mixing pool, environmental transmission, etc.

SexualNetwork

networks.SexualNetwork(self, **kwargs)

Base class for all sexual networks

StaticNet

networks.StaticNet(self, 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)