# Landscape Analysis¶

The neet module provides the LandscapeMixin class from which the neet.Network class inherits. This endows all networks with the various methods for computing the various landscape-related properties of the networks, such as LandscapeMixin.attractors. These properties are often associated with the state space of the network; however, we have opted to provide them via a separate mixin because the neet.StateSpace class represents an unstructured set of states, with no dynamical information

A key feature of the LandscapeMixin is that it is lazy and caches results as they are computed. For example, the attractors of the landscape are computed the first the user requests the LandscapeMixin.attractors property, but the result is cached in the LandscapeMixin.landscape_data attribute. Subsequent calls simply return the cached data. What’s more, many of the properties of the landscape can be determined using almost the exact same algorithm, so whenever one is requested, they are all simultaneously computed. See LandscapeMixin.expound for a list of such properties.

## LandscapeData¶

class neet.LandscapeData[source]

The LandscapeData class stores the various landscape properties computed in the LandscapeMixin. This is used rather an individual properties within LandscapeMixin to make it simple for users to extract all of the landscape properties before modifying a network and observing the effects of that change on the landscape.

The following properties are stored in LandscapeData:

 LandscapeMixin.transitions Get the state transitions as an array. LandscapeMixin.attractors Get the attractors of the landscape as an array. LandscapeMixin.attractor_lengths Get the length of the attractors as an array. LandscapeMixin.basins Get the basins of the states as an array. LandscapeMixin.basin_sizes Get the sizes of the attractor basins as an array. LandscapeMixin.basin_entropy Compute the basin entropy of the landscape [Krawitz2007]. LandscapeMixin.heights Get the heights of each state in the landscape. LandscapeMixin.recurrence_times Get the recurrence time of each state in the landscape. LandscapeMixin.in_degrees Get the in-degree of each state in the landscape.

Basic Usage

>>> s_pombe.attractors
array([array([76]), array([4]), array([8]), array([12]),
array([144, 110, 384]), array([68]), array([72]), array([132]),
array([136]), array([140]), array([196]), array([200]),
array([204])], dtype=object)
>>> default_landscape = s_pombe.landscape_data

>>> s_pombe.landscape(pin=[0,1]).attractors
array([array([0]), array([1]), array([386, 402, 178, 162]),
array([387, 403, 179, 163]), array([4]), array([8]), array([12]),
array([76]), array([65]), array([64]), array([68]), array([72]),
array([132]), array([136]), array([140]), array([192]),
array([193]), array([196]), array([200]), array([204])],
dtype=object)

>>> default_landscape.attractors
array([array([76]), array([4]), array([8]), array([12]),
array([144, 110, 384]), array([68]), array([72]), array([132]),
array([136]), array([140]), array([196]), array([200]),
array([204])], dtype=object)

>>> s_pombe.clear_landscape()


## LandscapeMixin¶

class neet.LandscapeMixin[source]

The LandscapeMixin class represents the structure and topology of the “landscape” of state transitions. That is, it is the state space together with information about state transitions and the topology of the state transition graph.

The LandscapeMixin class exposes the following methods:

 landscape Setup the landscape. clear_landscape Clear the landscape’s data and graph from memory. landscape_data Get the LandscapeData object. transitions Get the state transitions as an array. attractors Get the attractors of the landscape as an array. attractor_lengths Get the length of the attractors as an array. basins Get the basins of the states as an array. basin_sizes Get the sizes of the attractor basins as an array. basin_entropy Compute the basin entropy of the landscape [Krawitz2007]. heights Get the heights of each state in the landscape. recurrence_times Get the recurrence time of each state in the landscape. in_degrees Get the in-degree of each state in the landscape. trajectory Compute the trajectory from a given state. timeseries Compute a time series from all states. landscape_graph Construct a networkx.DiGraph of the state transitions. draw_landscape_graph Draw the state transition graph. expound Compute all cached data.
landscape(index=None, pin=None, values=None)[source]

Setup the landscape.

Prepares the landscape for computation of the various properties, specifying which nodes will be updated (index), pinned (pin) or set to a particular state (values). In particular, it computes the state transitions of the network and prepares private variables for a subsequent call to expound(), landscape_graph(), etc…

This function is implicitly called with no arguments by the various landscape accessors if it has not already been called. This is intended as a convenience since most of the time the user would do this anyway.

This function implicitly calls clear_landscape, so make sure to create a reference to landscape_data if landscape information has previously been compute and you wish to keep it around.

Basic Usage

>>> s_pombe.landscape_data.transitions
>>> s_pombe.landscape()
<neet.boolean.wtnetwork.WTNetwork object at 0x...>
>>> len(s_pombe.landscape_data.transitions)
512


Pinning States

# Prevents all states from transitioning
>>> s_pombe.landscape(pin = range(s_pombe.size))
<neet.boolean.wtnetwork.WTNetwork object at 0x...>
>>> np.array_equal(s_pombe.landscape_data.transitions, range(s_pombe.volume))
True
>>> s_pombe.clear_landscape()


Overriding Node States

# Forces all states to transition to 0
>>> s_pombe.landscape(values={i: 0 for i in range(s_pombe.size)})
<neet.boolean.wtnetwork.WTNetwork object at 0x...>
>>> np.all(s_pombe.landscape_data.transitions == 0)
True
>>> s_pombe.clear_landscape()

Parameters: index – the index to update (or None) pin – the indices to pin during update (or None) values – a dictionary of index-value pairs to set after update self
clear_landscape()[source]

Clear the landscape’s data and graph from memory.

landscape_data

Get the LandscapeData object.

The LandscapeData object contains any cached attractor landscape information generated by a call to expound().

transitions

Get the state transitions as an array. Each element of the array is the next (encoded) state of the system starting from the initial state equal to the index. For example, if

>>> net.transitions
array([ 0, 3, 1, 2 ])


then state 0 will transition to 0, 1 to 3, etc… Be aware that if landscape() has not been called, this method will call it.

Basic Usage

>>> s_pombe.transitions
array([  2,   2, 130, 130,   4,   0, 128, 128,   8,   0, 128, 128,  12,
0, 128, 128, 256, 256, 384, 384, 260, 256, 384, 384, 264, 256,
...
208, 208, 336, 336, 464, 464, 340, 336, 464, 464, 344, 336, 464,
464, 348, 336, 464, 464])


Pinned States

A preceding call to landscape() can, for example, pin specific nodes to their current state, thus affecting the state transitions.

>>> s_pombe.landscape(pin = [0]).transitions
array([  2,   3, 130, 131,   4,   1, 128, 129,   8,   1, 128, 129,  12,
1, 128, 129, 256, 257, 384, 385, 260, 257, 384, 385, 264, 257,
...
208, 209, 336, 337, 464, 465, 340, 337, 464, 465, 344, 337, 464,
465, 348, 337, 464, 465])
>>> s_pombe.clear_landscape()

Returns: a numpy.ndarray of state transitions
attractors

Get the attractors of the landscape as an array. Each element of the array is an attractor cycle, each of which is an array of states in the cycle. If landscape() has not been called, this method will implicitly call it.

Basic Usage

>>> s_pombe.attractors
array([array([76]), array([4]), array([8]), array([12]),
array([144, 110, 384]), array([68]), array([72]), array([132]),
array([136]), array([140]), array([196]), array([200]),
array([204])], dtype=object)


Update Only a Single Node

A preceding call to landscape() can, for example, specify which nodes will be updated in the process of computing the attractors. For example, we can allow only the first node of the state to be updated.

>>> s_pombe.landscape(index=0).attractors
array([[  0],
[  2],
[  4],
...
[506],
[508],
[510]])
>>> s_pombe.clear_landscape()

Returns: a numpy.ndarray of attractor cycles, each of which is an array of encoded states
attractor_lengths

Get the length of the attractors as an array. The array is indexed by the basin number. The order of the attractor lengths is the same as in attractors. For example,

>>> net.attractors
array([ array([0,1]), array([1]) ]
>>> net.attractor_lengths
array([2, 1])


If landscape() has not been called, this method will implicitly call it.

Basic Usage

>>> s_pombe.attractor_lengths
array([1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1])


Pinned States

A preceding call to landscape() can pin specific nodes to their current state, thus affecting the attractor lengths.

>>> s_pombe.landscape(pin = [0]).attractor_lengths
array([1, 6, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1])
>>> s_pombe.clear_landscape()

Returns: a numpy.ndarray of the lengths of the attractors
basins

Get the basins of the states as an array. Each index of the array is an encoded state and the corresponding value is the attractor basin in which it resides. The attractor basins are integers which can be used to index the attractors array, providing the attractor cycle for the base. For example, if

>>> net.basins
array([ 0, 1, 2, 1 ])
>>> net.attractors
array([ array([0]), array([1]), array([2]) ])


then the states 1 and 3 are both in the attractor basin which attracts to the fixed-point 1. If landscape() has not been called, this method will implicitly call it.

Basic Usage

>>> s_pombe.basins
array([ 0,  0,  0,  0,  1,  0,  0,  0,  2,  0,  0,  0,  3,  0,  0,  0,  0,
0,  4,  4,  0,  0,  4,  4,  0,  0,  4,  4,  0,  0,  4,  4,  4,  4,
...
0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
0,  0])


Resetting Node States

A preceding call to landscape() can, for example, specify that specific nodes are reset to a particular value after the updating the. For example, we can force the first and second nodes to 0, thus affecting the basins.

>>> s_pombe.landscape(values={0: 0, 1: 0}).basins
array([ 0,  0,  1,  1,  2,  0,  1,  1,  3,  0,  1,  1,  4,  0,  1,  1,  1,
1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
...
1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
1,  1])
>>> s_pombe.clear_landscape()

Returns: a numpy.ndarray of each state’s attractor basin
basin_sizes

Get the sizes of the attractor basins as an array. The array is indexed by the basin number. The order of the basin sizes is the same as in attractors. For example, if

>>> net.attractors
array([ array([0,1]), array([3,6]) ]
>>> net.basin_sizes
array([ 5, 3 ])


then the attractor [0, 1] has a basin size of $$5$$ with the remaining states in the other attractor’s basin. If landscape() has not been called, this method will implicitly call it.

Basic Usage

>>> s_pombe.basin_sizes
array([378,   2,   2,   2, 104,   6,   6,   2,   2,   2,   2,   2,   2])


Pinning States

A preceding call to landscape() can specify that some of the nodes are not updated, say the first two.

>>> s_pombe.landscape(pin=[0,1]).basin_sizes
array([  1,   4, 128, 128,   1,   1,   1, 114, 120,   1,   1,   1,   1,
1,   1,   1,   4,   1,   1,   1])
>>> s_pombe.clear_landscape()

Returns: a numpy.ndarray of each attractor’s basin size
basin_entropy

Compute the basin entropy of the landscape [Krawitz2007]. That is the Shannon entropy (in bits) of the distribution of basin sizes. For example,

>>> net.basin_sizes
array([6, 2])
>>> net.basin_entropy
0.8112781244591328


which is $$-\frac{6}{8}\log_2{\frac{6}{8}) - \frac{2}{8}\log_2{\frac{2}{8})$$. If landscape() has not been called, this method will implicitly call it.

Basic Usage

>>> s_pombe.basin_entropy
1.2218888...


Pinning States

A preceding call to landscape() can specify that some of the nodes are not updated, say the first two.

>>> s_pombe.landscape(pin=[0,1]).basin_entropy
2.328561849437885
>>> s_pombe.clear_landscape()

Returns: basin entropy in bits
heights

Get the heights of each state in the landscape. That is the fewest number of time steps from that state to a state in it’s attractor cycle, as an array. Each index of the array is an encoded state, and the corresponding value is the height. For example, if

>>> net.heights
array([ 3, 0, 1, ... ])


then it will take $$3$$ time steps for the state 0 to reach an attractor state while state 1 is an attractor state. If landscape() has not been called, this method will implicitly call it.

Basic Usage

>>> s_pombe.heights
array([7, 7, 6, 6, 0, 8, 6, 6, 0, 8, 6, 6, 0, 8, 6, 6, 8, 8, 1, 1, 2, 8,
1, 1, 2, 8, 1, 1, 2, 8, 1, 1, 2, 2, 2, 2, 9, 9, 1, 1, 9, 9, 1, 1,
...
3, 9, 9, 9, 3, 9, 9, 9, 3, 9, 9, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3])


Resetting Node States

A preceding call to landscape() can specify that specific nodes are reset to a particular value after the updating the. For example, we can force the first and second nodes to 0, thus affecting the basins.

>>> s_pombe.landscape(values={0: 0, 1: 0}).heights
array([0, 1, 6, 6, 0, 1, 6, 6, 0, 1, 6, 6, 0, 1, 6, 6, 2, 2, 5, 5, 2, 2,
5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 3, 3, 6, 6, 3, 3, 6, 6, 3, 3, 6, 6,
...
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3])
>>> s_pombe.clear_landscape()

Returns: a numpy.ndarray, each value of which is the height of the indexing state
recurrence_times

Get the recurrence time of each state in the landscape. That is the number of time steps from that state after which some state is repeated, as an array. Each index of the array is an encoded state, and the corresponding value is the recurrence time of that state. For example, if

>>> net.recurrent_times
array([ 3, 10, 0, ... ])


then a state will be seen at least twice if the 0 state is updated more than $$3$$ times. The 2 state is a fixed-point attractor state as updating even once will repeat a state. If landscape() has not been called, this method will implicitly call it.

Basic Usage

>>> s_pombe.recurrence_times
array([7, 7, 6, 6, 0, 8, 6, 6, 0, 8, 6, 6, 0, 8, 6, 6, 8, 8, 3, 3, 2, 8,
3, 3, 2, 8, 3, 3, 2, 8, 3, 3, 4, 4, 4, 4, 9, 9, 3, 3, 9, 9, 3, 3,
...
3, 9, 9, 9, 3, 9, 9, 9, 3, 9, 9, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3])


Resetting Node States

A preceding call to landscape() can specify that specific nodes are reset to a particular value after the updating the. For example, we can force the first and second nodes to 0, thus affecting the basins.

>>> s_pombe.landscape(pin=[0,1]).recurrence_times
array([0, 0, 5, 5, 0, 1, 5, 5, 0, 1, 5, 5, 0, 1, 5, 5, 2, 2, 4, 4, 2, 2,
4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 3, 3, 5, 5, 3, 3, 5, 5, 3, 3, 5, 5,
...
3, 3, 5, 5, 3, 3, 5, 5, 3, 3, 5, 5, 3, 3, 8, 8, 3, 3, 8, 8, 3, 3,
8, 8, 3, 3, 8, 8])
>>> s_pombe.clear_landscape()

Returns: a numpy.ndarray of recurrence times, one for each state
in_degrees

Get the in-degree of each state in the landscape. That is the number of states which transition to that state in a single time step, as a array. Each index of the array is an encoded state, and the corresponding value is the number of preceding states. For example, if

>>> net.in_degrees
array([ 5, 2, 0, 0, ... ]


then $$5$$ states transition to the 0 state in a single time step, while states 2 and 3 are in the Garden of Eden. If landscape() has not been called, this method will implicitly call it.

Basic Usage

>>> s_pombe.in_degrees
array([ 6,  0,  4,  0,  2,  0,  0,  0,  2,  0,  0,  0,  2,  0,  0,  0, 12,
0,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
...
0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
0,  0])


Pinning States

A preceding call to landscape() can specify that some of the nodes are not updated, say nodes 7 and 8.

>>> s_pombe.landscape(pin=[7,8]).in_degrees
array([36,  0,  6,  0,  2,  0,  0,  0,  2,  0,  0,  0,  2,  0,  0,  0, 42,
0,  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
...
0,  1,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
0,  0])
>>> s_pombe.clear_landscape()

Returns: a numpy.ndarray of the in-degree of each state
trajectory(init, timesteps=None, encode=None)[source]

Compute the trajectory from a given state.

This method computes a trajectory from init to the last before the trajectory begins to repeat. If timesteps is provided, then the trajectory will have a length of timesteps + 1 regardless of repeated states. The encode argument forces the states in the trajectory to be either encoded or not. When encode is None, whether or not the states of the trajectory are encoded is determined by whether or not the initial state (init) is provided in encoded form.

Note that when timesteps is None, the length of the resulting trajectory should be one greater than the recurrence time of the state.

If landscape() has not been called, this method will implicitly call it. Otherwise, it respects any settings provided by such a call.

Basic Usage

>>> s_pombe.trajectory([1,0,0,1,0,1,1,0,1])
[[1, 0, 0, 1, 0, 1, 1, 0, 1], ... [0, 0, 1, 1, 0, 0, 1, 0, 0]]

>>> s_pombe.trajectory([1,0,0,1,0,1,1,0,1], encode=True)
[361, 80, 320, 78, 128, 162, 178, 400, 332, 76]

>>> s_pombe.trajectory(361)
[361, 80, 320, 78, 128, 162, 178, 400, 332, 76]

>>> s_pombe.trajectory(361, encode=False)
[[1, 0, 0, 1, 0, 1, 1, 0, 1], ... [0, 0, 1, 1, 0, 0, 1, 0, 0]]

>>> s_pombe.trajectory(361, timesteps=5)
[361, 80, 320, 78, 128, 162]

>>> s_pombe.trajectory(361, timesteps=10)
[361, 80, 320, 78, 128, 162, 178, 400, 332, 76, 76]

Parameters: init (int or seq) – the initial state timesteps (int or None) – the number of time steps to include in the trajectory encode (bool or None) – whether to encode the states in the trajectory a list whose elements are subsequent states of the trajectory ValueError – if init an empty array ValueError – if timesteps is less than $$1$$
timeseries(timesteps)[source]

Compute a time series from all states.

This method computes a 3-dimensional array elements are the states of each node in the network. The dimensions of the array are indexed by, in order, the node, the initial state and the time step.

If landscape() has not been called, this method will implicitly call it. Otherwise, it respects any settings provided by such a call.

Basic Usage

>>> s_pombe.timeseries(5)
array([[[0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
...,
[1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0]],

[[0, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 0],
[1, 1, 1, 1, 0, 0],
...,
[0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0]],

...

[[0, 0, 1, 1, 1, 1],
[0, 0, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 0],
...,
[1, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0]],

[[0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 1],
...,
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 0, 0, 0]]])

Parameters: timesteps (int) – the number of timesteps to evolve the system a 3-D array of node states ValueError – if timesteps is less than $$1$$
landscape_graph(**kwargs)[source]

Construct a networkx.DiGraph of the state transitions.

If landscape() has not been called, this method will implicitly call it.

Basic Usage

>>> s_pombe.landscape_graph()
<networkx.classes.digraph.DiGraph object at 0x...>

Parameters: kwargs – kwargs to pass to networkx.DiGraph a networkx.DiGraph representing the state transition graph of the landscape
draw_landscape_graph(graphkwargs={}, pygraphkwargs={})[source]

Draw the state transition graph.

This method requires the optional dependency pygraphviz, which can be installed via pip. Be aware that pygraphviz requires native binaries of Graphviz which cannot be installed via pip.

If landscape() has not been called, this method will implicitly call it.

Basic Usage

>>> s_pombe.draw_landscape_graph()

Parameters: graphkwargs – kwargs to pass to landscape_graph pygraphkwargs – kwargs to pass to view_pygraphviz
expound()[source]

Compute all cached data.

This function performs the bulk of the calculations that the LandscapeMixin is concerned with. Most of the properties in this class are computed by this function whenever any one of them is requested and the results are cached. The advantage of this is that it saves computation time; why traverse the state space for every property call when you can do it all at once? The downside is that the cached results may use a good bit more memory. This is a trade-off that we are willing to make for now.

The properties that are computed by this function include:

 attractors Get the attractors of the landscape as an array. attractor_lengths Get the length of the attractors as an array. basins Get the basins of the states as an array. basin_sizes Get the sizes of the attractor basins as an array. basin_entropy Compute the basin entropy of the landscape [Krawitz2007]. heights Get the heights of each state in the landscape. recurrence_times Get the recurrence time of each state in the landscape. in_degrees` Get the in-degree of each state in the landscape.