# Sensitivity Analysis¶

class neet.boolean.SensitivityMixin[source]

SensitivityMixin provides methods for sensitivity analysis. That is, methods to quantify the degree to which perturbations of a network’s state propagate and spread. As part of this, we also provide methods for identifying “canalizing edges”: edges for which a state of the source node uniquely determines the state of the target regardless of other sources.

 sensitivity Compute the Boolean sensitivity at a given network state. average_sensitivity Calculate average Boolean network sensitivity, as defined in [Shmulevich2004]. lambdaQ Compute the sensitivity eigenvalue, $$\lambda_Q$$. difference_matrix Compute the difference matrix at a given state. average_difference_matrix Compute the difference matrix, averaged over some states. is_canalizing Determine whether a given network edge is canalizing. canalizing_edges Get the set of all canalizing edges in the network. canalizing_nodes Get a set of all nodes with at least one incoming canalizing edge.

The neet.boolean.BooleanNetwork class derives from SensitivityMixin to provide sensitivity analysis to all of Neet’s Boolean network models.

sensitivity(state, transitions=None)[source]

Compute the Boolean sensitivity at a given network state.

The sensitivity of a Boolean function $$f$$ on state vector $$x$$ is the number of Hamming neighbors of $$x$$ on which the function value is different than on $$x$$, as defined in [Shmulevich2004].

This method calculates the average sensitivity over all $$N$$ boolean functions, where $$N$$ is the number of nodes in the network.

Examples

>>> s_pombe.sensitivity([0, 0, 0, 0, 0, 1, 1, 0, 0])
1.0
>>> s_pombe.sensitivity([0, 1, 1, 0, 1, 0, 0, 1, 0])
0.4444444444444444
>>> c_elegans.sensitivity([0, 0, 0, 0, 0, 0, 0, 0])
1.75
>>> c_elegans.sensitivity([1, 1, 1, 1, 1, 1, 1, 1])
1.25


Optionally, the user can provide a pre-computed array of state transitions to improve performance when this function is repeatedly called.

>>> trans = list(map(s_pombe.decode, s_pombe.transitions))
>>> s_pombe.sensitivity([0, 0, 0, 0, 0, 1, 1, 0, 0], transitions=trans)
1.0
>>> s_pombe.sensitivity([0, 1, 1, 0, 1, 0, 0, 1, 0], transitions=trans)
0.4444444444444444

Parameters: state (list, numpy.ndarray) – a single network state transitions (list, numpy.ndarray, None) – precomputed state transitions (optional) the sensitivity at the provided state
average_sensitivity(states=None, weights=None, calc_trans=True)[source]

Calculate average Boolean network sensitivity, as defined in [Shmulevich2004].

The sensitivity of a Boolean function $$f$$ on state vector $$x$$ is the number of Hamming neighbors of $$x$$ on which the function value is different than on $$x$$.

The average sensitivity is an average taken over initial states.

Examples

>>> c_elegans.average_sensitivity()
1.265625
>>> c_elegans.average_sensitivity(states=[[0, 0, 0, 0, 0, 0, 0, 0],
... [1, 1, 1, 1, 1, 1, 1, 1]])
...
1.5
>>> c_elegans.average_sensitivity(states=[[0, 0, 0, 0, 0, 0, 0, 0],
... [1, 1, 1, 1, 1, 1, 1, 1]], weights=[0.9, 0.1])
...
1.7
>>> c_elegans.average_sensitivity(states=[[0, 0, 0, 0, 0, 0, 0, 0],
... [1, 1, 1, 1, 1, 1, 1, 1]], weights=[9, 1])
...
1.7

Parameters: states (list, numpy.ndarray, None) – The states to average over; all states if None weights (list, numpy.ndarray, None) – weights for a weighted average over states; all $$1$$. calc_trans – pre-compute all state transitions; ignored if states or weights is None. the average sensitivity of net
lambdaQ(**kwargs)[source]

Compute the sensitivity eigenvalue, $$\lambda_Q$$. That is, the largest eigenvalue of the sensitivity matrix average_difference_matrix().

This is analogous to the eigenvalue calculated in [Pomerance2009].

Examples

>>> s_pombe.lambdaQ()
0.8265021276831896
>>> c_elegans.lambdaQ()
1.263099227661824

Returns: the sensitivity eigenvalue ($$\lambda_Q$$) of net
difference_matrix(state, transitions=None)[source]

Compute the difference matrix at a given state.

For a network with $$N$$ nodes, with Boolean functions $$f_i$$, the difference matrix is a $$N \times N$$ matrix

$A_{ij} = f_i(x) \oplus f_i(x \oplus e_j)$

where $$e_j$$ is the network state with the $$j$$-th node in the $$1$$ state while all others are $$0$$. In other words, the element $$A_{ij}$$ signifies whether or not flipping the $$j$$-th node’s state changes the subsequent state of the $$i$$-th node.

Examples

>>> s_pombe.difference_matrix([0, 0, 0, 0, 0, 0, 0, 0, 0])
array([[0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 1., 1., 1., 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0., 0., 0., 1.],
[0., 0., 0., 1., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 0., 1., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 1., 0.],
[0., 0., 0., 0., 0., 0., 1., 0., 1.],
[0., 1., 0., 0., 0., 0., 0., 1., 0.],
[0., 0., 0., 0., 1., 0., 0., 0., 0.]])
>>> c_elegans.difference_matrix([0, 0, 0, 0, 0, 0, 0, 0])
array([[1., 0., 0., 0., 0., 0., 0., 1.],
[0., 0., 1., 1., 0., 0., 0., 0.],
[0., 0., 1., 0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 1., 0., 1.],
[0., 0., 0., 0., 0., 1., 1., 0.],
[1., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 1.]])

Parameters: state (list, numpy.ndarray) – the starting state transitions (list, numpy.ndarray, None) – precomputed state transitions (optional) the difference matrix
average_difference_matrix(states=None, weights=None, calc_trans=True)[source]

Compute the difference matrix, averaged over some states.

Examples

>>> s_pombe.average_difference_matrix()
array([[0.    , 0.    , 0.    , 0.    , 0.    , 0.    , 0.    , 0.    ,
0.    ],
[0.    , 0.    , 0.25  , 0.25  , 0.25  , 0.    , 0.    , 0.    ,
0.    ],
[0.25  , 0.25  , 0.25  , 0.    , 0.    , 0.25  , 0.    , 0.    ,
0.25  ],
[0.25  , 0.25  , 0.    , 0.25  , 0.    , 0.25  , 0.    , 0.    ,
0.25  ],
[0.    , 0.    , 0.    , 0.    , 0.    , 1.    , 0.    , 0.    ,
0.    ],
[0.    , 0.    , 0.0625, 0.0625, 0.0625, 0.    , 0.0625, 0.0625,
0.    ],
[0.    , 0.5   , 0.    , 0.    , 0.    , 0.    , 0.5   , 0.    ,
0.5   ],
[0.    , 0.5   , 0.    , 0.    , 0.    , 0.    , 0.    , 0.5   ,
0.5   ],
[0.    , 0.    , 0.    , 0.    , 1.    , 0.    , 0.    , 0.    ,
0.    ]])
>>> c_elegans.average_difference_matrix()
array([[0.25  , 0.25  , 0.    , 0.    , 0.    , 0.25  , 0.25  , 0.25  ],
[0.    , 0.    , 0.5   , 0.5   , 0.    , 0.    , 0.    , 0.    ],
[0.5   , 0.    , 0.5   , 0.    , 0.5   , 0.    , 0.    , 0.    ],
[0.    , 0.    , 1.    , 0.    , 0.    , 0.    , 0.    , 0.    ],
[0.    , 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.    , 0.3125],
[0.5   , 0.    , 0.    , 0.    , 0.    , 0.5   , 0.5   , 0.    ],
[1.    , 0.    , 0.    , 0.    , 0.    , 0.    , 0.    , 0.    ],
[0.    , 0.    , 0.    , 0.    , 0.    , 0.    , 0.5   , 0.5   ]])

Parameters: states (list, numpy.ndarray, None) – the states to average over; all states if None weights (list, numpy.ndarray, None) – weights for a weighted average over states; uniform weighting if None calc_trans (bool) – pre-compute all state transitions; ignored if states or weights is None the difference matrix as a numpy.ndarray().
is_canalizing(x, y)[source]

Determine whether a given network edge is canalizing.

An edge $$(y,x)$$ is canalyzing if $$x$$’s value at $$t+1$$ is fully determined when $$y$$’s value has a particular value at $$t$$, regardless of the values of other nodes.

According to (Stauffer 1987):

"A rule [...] is called forcing, or canalizing, if at least one of
its :math:K arguments has the property that the result of the
function is already fixed if this argument has one particular
value, regardless of the values for the :math:K-1 other
arguments."  Note that this is a definition for whether a node's
rule is canalizing, whereas this function calculates whether a
specific edge is canalizing.  Under this definition, if a node has
any incoming canalizing edges, then its rule is canalizing.


Examples

>>> s_pombe.is_canalizing(1, 2)
True
>>> s_pombe.is_canalizing(2, 1)
False
>>> c_elegans.is_canalizing(7, 7)
True
>>> c_elegans.is_canalizing(1, 3)
True
>>> c_elegans.is_canalizing(4, 3)
False

Parameters: x (int) – target node’s index y (int) – source node’s index whether or not the edge (y,x) is canalizing; None if the edge does not exist
canalizing_edges()[source]

Get the set of all canalizing edges in the network.

Examples

>>> s_pombe.canalizing_edges()
{(1, 2), (5, 4), (0, 0), (1, 3), (4, 5), (5, 6), (5, 7), (1, 4), (8, 4), (5, 2), (5, 3)}
>>> c_elegans.canalizing_edges()
{(1, 2), (3, 2), (1, 3), (7, 6), (6, 0), (7, 7)}

Returns: the set of canalizing edges as in the form (target, source)
canalizing_nodes()[source]

Get a set of all nodes with at least one incoming canalizing edge.

Examples

>>> s_pombe.canalizing_nodes()
{0, 1, 4, 5, 8}
>>> c_elegans.canalizing_nodes()
{1, 3, 6, 7}

Returns: the set indices of nodes with at least one canalizing input edge