Recursive exclusion: how complexes divide a substrate#

Download this page as a Jupyter notebook Open in Colab

The exclusion postulate says that candidate systems sharing units cannot both exist: among overlapping candidates, only one specifies its cause–effect structure. PyPhi applies the postulate recursively (Marshall et al., 2023): candidates are walked in descending order of system integrated information \(\varphi_s\), each accepted complex claims its units, and a candidate excluded by an accepted complex no longer exists, so it cannot exclude anything else in turn.

This recursion has a consequence worth stating explicitly: a complex can coexist with an overlapping candidate of higher \(\varphi_s\), as long as that candidate was itself excluded by some other complex. This tutorial builds a small substrate where that happens, finds its complexes, and reads the exclusion records and selection margins that document who beat whom.

import numpy as np

import pyphi

pyphi.config.progress_bars = False

A chain of decaying couplings#

Four units A, B, C, D in a chain, with reciprocal coupling strengths that decay along it: A–B couple strongly (0.6), B–C moderately (0.3), C–D weakly (0.15). Each unit’s probability of turning on is a baseline 0.05, plus 0.05 times its own state, plus the coupled inputs.

n = 4
weights = np.zeros((n, n))
weights[0, 1] = weights[1, 0] = 0.6
weights[1, 2] = weights[2, 1] = 0.3
weights[2, 3] = weights[3, 2] = 0.15
for i in range(n):
    weights[i, i] = 0.05

tpm = np.zeros((2**n, n))
for row in range(2**n):
    state = np.array([(row >> k) & 1 for k in range(n)])
    tpm[row] = 0.05 + weights @ state

substrate = pyphi.Substrate(tpm, node_labels=("A", "B", "C", "D"))
state = (0, 0, 0, 0)

By construction the \(\varphi_s\) landscape is a chain: \(\{A,B\} > \{B,C\} > \{C,D\}\), with \(\{B,C\}\) overlapping both of its neighbors.

Finding the complexes#

found = substrate.complexes(state)

for complex_ in found:
    print(complex_.node_indices, float(complex_.phi))
(0, 1) 0.14800116288755374
(2, 3) 0.03710393588291759

Both \(\{A,B\}\) and \(\{C,D\}\) are complexes. A non-recursive reading of exclusion would reject \(\{C,D\}\): it overlaps \(\{B,C\}\), which has higher \(\varphi_s\). But \(\{B,C\}\) overlaps \(\{A,B\}\), which has higher \(\varphi_s\) still — so \(\{B,C\}\) is excluded first, and once excluded it does not exist and has no standing to exclude \(\{C,D\}\). The recursion carves the substrate from the top down, and \(\{C,D\}\) is the maximum among the candidates that remain.

Excluded candidates with higher φₛ#

Each complex records the overlapping candidates excluded in its favor:

from pyphi import numerics

cd = found[1]
phi = float(cd.phi)
for record in sorted(cd.excluded, key=lambda r: -r.phi):
    beaten = record.phi < phi or numerics.eq(record.phi, phi)
    print(f"{record.node_indices}  φₛ={record.phi:.4f}  [{'beaten' if beaten else 'excluded earlier'}]")
(1, 2)  φₛ=0.1041  [excluded earlier]
(0, 1, 2)  φₛ=0.1000  [excluded earlier]
(0, 1, 2, 3)  φₛ=0.0564  [excluded earlier]
(1, 2, 3)  φₛ=0.0546  [excluded earlier]
(2,)  φₛ=0.0227  [beaten]
(3,)  φₛ=0.0208  [beaten]

\(\{C,D\}\)’s records contain candidates with higher \(\varphi_s\) than \(\{C,D\}\) itself — \(\{B,C\}\) among them. They have more integrated information than the complex, and were excluded by a different complex before this one was accepted. They document the recursion at work: they were never rivals that \(\{C,D\}\) had to beat.

Selection margins#

How decisively did each complex win? The exclusion_margin of a Complex reports the \(\varphi_s\) gap to the best overlapping rival the complex actually beat — candidates excluded earlier by another complex do not enter the margin:

for complex_ in found:
    print(
        complex_.node_indices,
        f"φₛ={float(complex_.phi):.4f}",
        f"margin={complex_.exclusion_margin:.4f}",
    )
(0, 1) φₛ=0.1480 margin=0.0439
(2, 3) φₛ=0.0371 margin=0.0144

\(\{A,B\}\) beat its strongest overlapping rival, \(\{B,C\}\), by about \(0.04\). \(\{C,D\}\) beat only the singletons \(\{C\}\) and \(\{D\}\), and its margin measures the gap to the best of them. A margin of zero (equivalently, complex_.effectively_tied) would mean an overlapping rival tied at the configured precision and the selection was decided by criteria beyond \(\varphi_s\); see Control tie-breaking for how ties are resolved.

References#

  • Marshall W, et al. (2023). System integrated information. Entropy 25(2):334, Algorithm A1.

  • Albantakis L et al. (2023). Integrated information theory (IIT) 4.0. PLoS Computational Biology 19(10):e1011465 (the exclusion postulate).