Wiring Diagram
Wiring-diagram representation for dynamical systems.
This module defines the WiringDiagram class, which encodes
the directed regulatory topology of a dynamical system independently of any
update functions.
A wiring diagram specifies, for each node, the set of regulating nodes (predecessors). Nodes with no regulators are source nodes in the wiring diagram. Whether such nodes act as constants or identity nodes in dynamical systems can only be determined after dynamical update functions are assigned.
- class boolforge.wiring_diagram.WiringDiagram(I: Sequence[Sequence[int]], variables: list[str] | ndarray | None = None, weights: Sequence[Sequence[float]] | None = None)[source]
Bases:
WiringDiagramInteroperabilityMixin,WiringDiagramModularityMixin,WiringDiagramMotifMixin,WiringDiagramPlottingMixinDirected wiring diagram for a dynamical system.
A wiring diagram specifies the regulatory topology of a dynamical system by listing, for each node, the indices of its regulators (incoming edges). It does not encode dynamical update functions or dynamical rules.
Nodes with zero indegree are source nodes. Whether a source node represents a constant, an identity node, or a dynamic variable is determined only after dynamical update functions are assigned.
Parameters
- Isequence of sequences of int
Adjacency-list representation of the wiring diagram. Entry
I[i]contains the indices of nodes regulating nodei. Regulator lists may have variable length.- variableslist[str] or np.ndarray[str], optional
Names of the variables corresponding to each node. Must have length
Nif provided. If None, default names['x0', 'x1', ..., 'x{N-1}']are assigned.- weightssequence of sequences of float, optional
Interaction weights corresponding to
I. Entryweights[i][j]gives the weight of the interaction from regulatorI[i][j]to nodei. Missing interactions may be encoded asnp.nan.
Attributes
- Ilist[np.ndarray]
Regulator index arrays, one per node.
- variablesnp.ndarray[str]
Names of variables corresponding to each node.
- Nint
Total number of nodes, including source nodes.
- indegreesnp.ndarray[int]
Indegree of each node.
- outdegreesnp.ndarray[int]
Outdegree of each node.
- weightslist[np.ndarray] or None
Interaction weights associated with
Iif provided.
Notes
Node indices are zero-based.
Source nodes are identified solely by indegree == 0.
The wiring diagram encodes topology only and does not define dynamics.
Examples
Nodes with zero indegree are interpreted as source nodes.
>>> from boolforge import WiringDiagram >>> I = [ [], # node 0 has no regulators -> source node [0], # node 1 is regulated by node 0 [0, 1], # node 2 is regulated by nodes 0 and 1 ] >>> W = WiringDiagram(I)
>>> W.N 3
>>> W.get_source_nodes(as_dict=True) {0: True, 1: False, 2: False}
>>> W.get_source_nodes(as_dict=False) array([0])
See Also
boolforge.BooleanNetwork
- get_outdegrees() ndarray[source]
Compute the outdegree of each node.
The outdegree of a node is the number of nodes it regulates, i.e., the number of outgoing edges from that node in the wiring diagram.
Returns
- np.ndarray
One-dimensional array of length
Ncontaining the outdegree of each node.
- __weakref__
list of weak references to the object
- classmethod from_DiGraph(nx_DiGraph: nx.DiGraph) WiringDiagram
Construct a WiringDiagram from a NetworkX directed graph.
Each node in the directed graph represents a Boolean variable, and each directed edge
u -> vindicates that variableuregulates variablev.Parameters
- nx_DiGraphnx.DiGraph
Directed graph whose nodes represent variables and whose edges represent regulatory interactions.
- Node attributes (optional)
- namestr
Name of the variable. If not provided, the node label is used when possible.
- Edge attributes (optional)
- weightfloat
Weight of the regulatory interaction from
utov. If present on all edges, weights are stored in theweightsattribute of the resulting WiringDiagram.
Returns
- WiringDiagram
Wiring diagram representing the topology of the directed graph.
Notes
Nodes are ordered according to the iteration order of
nx_DiGraph.nodes.Regulator lists are constructed from incoming edges (graph predecessors).
Edge weights are only stored if all edges define a
'weight'attribute.
Examples
>>> import networkx as nx >>> from boolforge import WiringDiagram >>> G = nx.DiGraph() >>> G.add_edges_from([(0, 1), (1, 2)]) >>> W = WiringDiagram.from_DiGraph(G) >>> W.I [array([], dtype=int64), array([0]), array([1])] >>> W.get_source_nodes() {0: True, 1: False, 2: False}
- get_fbls(max_length: int = 4, classify: bool = False) dict
Identify feedback loops (simple directed cycles).
A feedback loop is defined as a simple directed cycle in the underlying wiring diagram. This method enumerates elementary circuits using a variant of Johnson’s algorithm, restricted to cycles of length at most
max_length.Parameters
- max_lengthint, optional
Maximum length of feedback loops to consider. Cycles longer than
max_lengthare not returned. Default is 4.- classifybool, optional
If True and interaction weights are available, the type of each feedback loop is determined.
Returns
- dict
list of list of int List of feedback loops, where each loop is represented as a list of node indices forming a directed cycle. Self-loops are returned as single-element lists.
- get_ffls() tuple[list[list[int]], list[list[float]] | None]
Identify feed-forward loops (FFLs) in the wiring diagram.
A feed-forward loop is a triplet of nodes
(i, j, k)such thati -> j,j -> k, andi -> kare all regulatory interactions.Returns
- tuple
A tuple
(ffls, types)where:fflsis a list of feed-forward loops, each represented as[i, j, k].typesis a list of corresponding edge-weight triplets[i -> k, i -> j, j -> k]if interaction weights are defined, orNoneotherwise.
- get_modular_structure() set[tuple[int, int]]
Compute the modular (condensation) structure of the wiring diagram.
The modular structure is represented as a directed acyclic graph (DAG) whose nodes correspond to strongly connected components (SCCs) of the wiring diagram. A directed edge
(i, j)indicates that there exists at least one regulatory interaction from SCCito SCCj.Returns
- set of tuple of int
Set of directed edges representing the condensation DAG, where each edge
(i, j)denotes a regulation from SCCito SCCj.
Notes
SCC indices correspond to the ordering returned by
get_strongly_connected_components.
- get_source_nodes(as_dict: bool = True) dict[int, bool] | ndarray[source]
Identify source nodes in the wiring diagram.
A source node is a node with zero indegree. Source nodes represent inputs to the wiring diagram; whether they act as constants or identity nodes in dynamical systems depends on the associated dynamical update functions and is not determined at the wiring-diagram level.
Parameters
- as_dictbool, optional
If True (default), return a dictionary mapping node indices to Boolean values indicating whether each node is a source node. If False, return an array of indices corresponding to source nodes.
Returns
- dict[int, bool] or np.ndarray
If
as_dictis True, a dictionary where keys are node indices and values indicate whether the node is a source node. Ifas_dictis False, a one-dimensional array containing the indices of source nodes.
- get_strongly_connected_components() list
Compute the strongly connected components of the wiring diagram.
A strongly connected component (SCC) is a maximal set of nodes such that every node in the set is reachable from every other node via directed paths.
Returns
- list of set of int
List of strongly connected components, where each component is represented as a set of node indices.
- plot(max_expanded_sccs: int = 4, min_scc_size: int = 2, show: bool = True, curviness: float = 0.25)
Plot an integrated overview of the wiring diagram.
- The plot consists of:
A top panel showing the modular structure of the network as a DAG of strongly connected components (SCCs).
Bottom panels showing the internal wiring of selected SCCs using a circular layout.
By default, the largest SCCs of size >=
min_scc_sizeare expanded, up tomax_expanded_sccs.Parameters
- max_expanded_sccsint, default=4
Maximum number of SCCs to expand and show in detail.
- min_scc_sizeint, default=2
Minimum SCC size to be eligible for expansion.
- showbool, default=True
Whether to call
plt.show()at the end.- curvinessfloat, default=0.25
Curvature of edges spanning multiple layers in the modular graph (0 = straight).
Returns
- figmatplotlib.figure.Figure
The created figure.
- plot_modular_structure(ax=None, show=True, node_labels: bool = True, max_nodes: int = 50, curviness: float = 0.25)
Plot the wiring diagram as a directed acyclic graph of strongly connected components.
The wiring diagram is first condensed into its strongly connected components (SCCs), yielding a directed acyclic graph (DAG). Each node in the plot represents one SCC.
The layout is hierarchical (top-to-bottom) using topological generations, making feed-forward structure visually apparent, while condensing feedback loops.
Parameters
- axmatplotlib.axes.Axes, optional
Axis to draw on. If None, a new figure and axis are created.
- showbool, default=True
Whether to call
plt.show()after plotting.- node_labelsbool, default=True
Whether to label SCC nodes by their size (only shown for SCCs of size > 1).
- max_nodesint, default=50
If the number of SCCs exceeds this value, edges are sparsified to reduce clutter.
- curvinessfloat, default=0.25
Curvature of edges spanning multiple layers (0 = straight).
Returns
- axmatplotlib.axes.Axes
The axis containing the plot.
- to_DiGraph(use_variable_names: bool = True) DiGraph
Convert the wiring diagram into a NetworkX directed graph.
A directed edge
u -> vindicates that nodeuregulates nodev.Parameters
- use_variable_namesbool, optional
If True (default), nodes are labeled using the variable names stored in
self.variables. If False, nodes are labeled by integer indices0, 1, ..., N-1.
Returns
- nx.DiGraph
Directed graph representing the wiring diagram. If interaction weights are present, they are stored as edge attributes under the key
'weight'.
Notes
The node ordering follows the internal ordering of the wiring diagram.
Incoming edges of node
icorrespond to the regulators listed inself.I[i].Edge weights are included only if the wiring diagram defines weights.