pyphi.substrate.Substrate#

class pyphi.substrate.Substrate(tpm=None, cm=None, node_labels=None, *, marginals=None, state_space=None, alphabet=None)[source]#

Bases: Displayable, ToPandasMixin, Serializable

A substrate of nodes.

Represents the substrate under analysis and holds auxiliary data about it.

The TPM is stored canonically as a FactoredTPM (per-node-factored conditional). substrate.tpm returns this FactoredTPM directly. The joint conditional ndarray is available on demand via joint_tpm().

Two mutually exclusive forms of TPM input are accepted — exactly one must be supplied:

  • Joint form (tpm=): a standard joint conditional array. Accepted shapes are 2-D state-by-node (s, n), 2-D state-by-state (s, s), or multidimensional state-by-node [2]*n + [n]. Row indices follow the little-endian convention (see Little-endian convention). Passing a FactoredTPM via tpm= raises ValueError; use marginals= or from_factored() instead.

  • Factored form (marginals=): a sequence of per-node conditional arrays, one per node. Each factor has shape (*alphabet_sizes, alphabet_size_i).

Parameters:
  • tpm (numpy.ndarray) – The joint transition probability matrix of the substrate (joint form only — see above).

  • cm (numpy.ndarray, optional) – A square binary adjacency matrix indicating the connections between nodes in the substrate. cm[i][j] == 1 means that node i is connected to node j (see Connectivity matrix conventions). If no connectivity matrix is given, PyPhi assumes that every node is connected to every node (including itself).

  • node_labels (tuple[str] or NodeLabels, optional) – Human-readable labels for each node in the substrate.

  • marginals (sequence of numpy.ndarray, optional) – Per-node conditional arrays (factored form). Mutually exclusive with tpm.

  • state_space (optional) – The state space for the substrate nodes. Accepts a uniform-flat integer alphabet size, a tuple of per-node label tuples ((labels_0, ...), (labels_1, ...), ...), or a single flat tuple of labels applied uniformly to every node. When None, defaults to binary (0, 1) per node.

  • alphabet (int, optional) – Shortcut for a uniform integer alphabet of the given size — equivalent to state_space=tuple(range(alphabet)). Mutually exclusive with state_space.

See also

from_factored

Build a Substrate directly from an existing FactoredTPM.

Examples

In a 3-node binary substrate, the_substrate.joint_tpm()[(0, 0, 1)] gives, for each node at t, the per-alphabet-value distribution given that the state at t − 1 was N₀ = 0, N₁ = 0, N₂ = 1; e.g. the_substrate.joint_tpm()[(0, 0, 1)][i, 1] is the probability that node i at t takes value 1.

property tpm: FactoredTPM#

The per-node-factored conditional TPM of the substrate.

property factored_tpm: FactoredTPM#

Alias for tpm — explicit per-node-factored access.

property state_space: tuple[tuple[Any, ...], ...]#

Per-node label tuples, delegated from the underlying FactoredTPM.

joint_tpm()[source]#

The joint conditional TPM as a read-only JointTPM view.

The joint peer of tpm (the factored form). Materializes P(sₜ₊₁ | sₜ) from the factored storage in the explicit-alphabet layout [a_1, ..., a_N, N, max_alphabet] for both binary and k-ary substrates: per row, axis -1 holds factor i’s distribution in slots [:alphabet_sizes[i]], with trailing slots zero when alphabets are heterogeneous. The returned view is array-convertible (numpy.asarray) and indexable. Recomputes on every call (no cache); callers needing it repeatedly should cache locally.

Return type:

JointTPM

classmethod from_factored(factored, cm=None, node_labels=None)[source]#

Construct a Substrate from an existing FactoredTPM.

Parameters:
Return type:

Substrate

property cm: ConnectivityMatrix#

The substrate’s connectivity matrix.

A square binary adjacency matrix indicating the connections between nodes in the substrate.

Type:

np.ndarray

property connectivity_matrix: ConnectivityMatrix#

Alias for cm.

Type:

np.ndarray

property causally_significant_nodes: NodeIndices#

See pyphi.connectivity.causally_significant_nodes().

property size: int#

The number of nodes in the substrate.

Type:

int

property num_states: int#

The number of possible states of the substrate.

Type:

int

property node_indices: NodeIndices#

The indices of nodes in the substrate.

This is equivalent to tuple(range(substrate.size)).

Type:

tuple[int]

property node_labels: NodeLabels#

The labels of nodes in the substrate.

Type:

tuple[str]

potential_purviews(direction, mechanism, max_order=None)[source]#

All purviews which are not clearly reducible for a mechanism.

Depends only on connectivity, so the result is cached on _cm_fingerprint and shared across every substrate with the same cm (a parameter sweep over a fixed topology reuses it). The cache key includes max_order, so bounded and unbounded results never alias.

Parameters:
  • direction (Direction) – CAUSE or EFFECT.

  • mechanism (tuple[int, ...]) – The mechanism which all purviews are checked for reducibility over.

  • max_order (int, optional) – Enumerate only purviews of at most this many units. Since reducibility is checked per purview, the result equals the unbounded result filtered to the cap — but the enumeration never constructs the larger candidates, which matters on large substrates. If None, all orders are enumerated.

Returns:

list[tuple[int, …]] – All purviews which are irreducible over mechanism.

Return type:

list[Purview]

sia(state, indices=None, **kwargs)[source]#

Return the SIA of a single candidate system over this substrate.

Parameters:
  • state (tuple[int, ...])

  • indices (NodeIndices | None)

  • kwargs (Any)

Return type:

Any

ces(state, indices=None, **kwargs)[source]#

Return the cause-effect structure of a single candidate system.

Parameters:
  • state (tuple[int, ...])

  • indices (NodeIndices | None)

  • kwargs (Any)

Return type:

Any

all_sias(state, candidates=None, **kwargs)[source]#

Return SIAs for every candidate system; see all_sias().

Parameters:
Return type:

list[Any]

irreducible_sias(state, candidates=None, **kwargs)[source]#

Return SIAs with φₛ > 0; see irreducible_sias().

Parameters:
Return type:

list[Any]

complexes(state, candidates=None, **kwargs)[source]#

Return the substrate’s complexes as Complex objects; see complexes().

Parameters:
Return type:

tuple[Any, …]

maximal_complex(state, candidates=None, **kwargs)[source]#

Return the maximal Complex; see maximal_complex().

Parameters:
Return type:

Any

to_networkx(connectivity='inferred')[source]#

Return a node-labeled networkx.DiGraph of the substrate.

By default edges are the TPM-inferred causal connectivity; pass connectivity="declared" to use the declared cm verbatim. Requires the visualize extra (networkx).

Parameters:

connectivity (str)

Return type:

Any

classmethod from_networkx(graph, tpm, *, node_labels=None)[source]#

Build a Substrate from a networkx DiGraph topology and a TPM.

The graph supplies connectivity and node order; tpm supplies the dynamics (required). A graph that omits an edge the TPM implies is rejected.

Parameters:
Return type:

Substrate

to_graphml(path, connectivity='inferred')[source]#

Write the substrate graph to a GraphML file (see to_networkx()).

Parameters:
  • path (str)

  • connectivity (str)

Return type:

None

to_adjacency(connectivity='inferred')[source]#

Return the connectivity matrix as a node-labeled pandas.DataFrame.

Parameters:

connectivity (str)

Return type:

Any

to_dbn()[source]#

Return the substrate’s 2-timeslice DBN as a networkx.DiGraph.

Each node X becomes (X, 0) and (X, 1); inter-slice edges run (parent, 0) -> (child, 1) over the node’s inferred parents, so the graph is acyclic. (X, 1) nodes carry cpd and parents attributes. Requires the visualize extra (networkx).

Return type:

Any

to_dbn_dict()[source]#

Return the substrate’s 2-timeslice DBN as a plain dict.

Keys "variables", "edges" (inter-slice (parent, child)), and "cpds" (label -> {"parents", "table"}). Pure numpy; no networkx import.

Return type:

dict

inactivate(fixed)[source]#

Return a copy with the given units frozen in a state.

Each unit in fixed (by index or label) is conditioned into every other unit’s transition factor at the given state, so it has no counterfactual states and cannot be intervened upon. Node labels are preserved. Inputs from a frozen unit become fixed biases, and its row of the connectivity matrix is cleared.

Albantakis et al. (2023, Fig 7) distinguish an inactive unit, in its OFF state and still contributing distinctions and relations, from an inactivated one, whose cause-effect power is abolished (Fig 7C): the complex that contained it shrinks. Inactivation is also distinct from holding a unit as a background condition of a candidate system: a background unit is causally marginalized, held at its current state for effects and with its past states weighted by their probability given the current state for causes (2023, Eqs. 3-4); an inactivated unit has no alternative states.

Parameters:

fixed (Mapping[int or str, int]) – Units (indices or labels) mapped to the state index each is frozen in.

Returns:

Substrate

Raises:
  • ValueError – If a unit index is out of range or a state is outside the unit’s alphabet.

  • KeyError – If a unit label is unknown.

Return type:

Substrate

Examples

>>> from pyphi import examples
>>> lesioned = examples.iit4_2023_fig7_substrate().inactivate({"E": 0})
>>> lesioned.size
5