The IIT 4.0 demo notebook#

Download the notebook Open in Colab

This notebook is the supplement to the IIT 4.0 paper (Albantakis et al. 2023). It walks through a full IIT 4.0 analysis in PyPhi and reproduces the paper’s numbers on the paper’s own example systems.

The paper’s \(\varphi_s\) values were computed before the system’s intrinsic information became part of the definition of \(\varphi_s\), so the notebook pins the version of IIT the paper used (see Reproduce results from earlier versions of IIT).

Part 1 works through a System Irreducibility Analysis one IIT postulate at a time (intrinsicality, information, integration (\(\varphi_s\)), exclusion, and composition) on the deterministic three-node A/B/C system from Figure 8C. Part 2 reproduces Figures 1, 2, and 4 on the nondeterministic Ising network used in the main text, going deeper into the algorithmic computation of complexes, distinctions, and relations.

The outputs shown here are stored with the notebook. For the theory behind each step, see the Theory section; for a shorter hands-on tour, see A complete worked example.

PyPhi is a software toolbox that provides the reference implementation of Integrated Information Theory (IIT).

This notebook accompanies the IIT 4.0 paper, available here, and is written for PyPhi 2.0.

Installing PyPhi#

First, we use pip to install PyPhi and its dependencies:

# Colab: install PyPhi first. Skip this cell in a local environment that has it.
!python -m pip install -U git+https://github.com/wmayner/pyphi.git@main
import pyphi
import numpy as np

from pyphi.measures.distribution import (
    resolve_mechanism_measure,
    resolve_system_measure,
)

pyphi.config.progress_bars = False
pyphi.config.parallel = False
# This notebook deliberately evaluates every system partition, so we turn off
# the short-circuit that stops as soon as a system is found to be reducible.
pyphi.config.shortcircuit_sia = False

# Reproduce the paper's values under the version of IIT it used.
import warnings

from pyphi.conf import presets

with warnings.catch_warnings():
    warnings.simplefilter("ignore")  # advisory config-change notices
    pyphi.config.iit = presets.iit4_2023["iit"]

# The high-level entry points (`pyphi.analyze`, `System.sia`, ...) resolve the
# measures for intrinsic information and system integration from config
# automatically. A few cells below call the lower-level machinery directly,
# which in PyPhi 2.0 takes these measures as explicit arguments; we resolve
# them here from the current configuration so those cells can pass them in.
specification_measure = resolve_mechanism_measure(
    pyphi.config.formalism.iit.specification_measure
)
system_measure = resolve_system_measure(
    pyphi.config.formalism.iit.system_phi_measure
)
<function pyphi.measures.distribution.generalized_intrinsic_difference(forward_repertoire: 'ArrayLike', partitioned_forward_repertoire: 'ArrayLike', selectivity_repertoire: 'ArrayLike', state: 'State | None' = None) -> 'Repertoire | float'>

Defining a substrate#

The first part of the tutorial will be based on the second deterministic system from Figure 8C of the IIT 4.0 paper: “Functionally equivalent networks with different Φ-structures”.

IIT_4.0_demo_system.png

Background conditions (nodes “I” and “O”) have already been fixed to “I”=ON, “O”=ON in the hypothetical 5-node Transition Probability Matrix (TPM). Therefore, we will start from a TPM which only contains nodes “A”, “B”, “C”.

node_labels = ("A", "B", "C")

# TPM in state-by-node format (see `help(pyphi.Substrate)` for information on TPM
# representations).
tpm = np.array(
    [
        [1, 0, 0],
        [0, 1, 0],
        [1, 1, 1],
        [0, 1, 1],
        [0, 0, 0],
        [1, 1, 0],
        [0, 0, 1],
        [1, 0, 1],
    ]
)

# The network's adjacency matrix. In its absence, PyPhi will assume all-to-all
# connectivity. PyPhi uses the "from-to" convention: a "1" in entry (i,j) means
# there is a directed edge from unit i to unit j.

# NOTE: If the adjacency matrix indicates a connection between units when there
# is no causal connection according to the TPM, the analysis will correctly
# determine that; however, if the matrix specifies the *lack* of a connection,
# PyPhi will assume no causal influence and short-circuit the analysis, even if
# the TPM implies that there is.
connectivity_matrix = np.array([
    [1, 1, 0,],  # A->A, A->B
    [0, 1, 1,],  # B->B, B->C
    [1, 1, 1,],  # C->A, C->B, C->C
])
array([[1, 1, 0],
       [0, 1, 1],
       [1, 1, 1]])

We begin by instantiating a Substrate object. This represents the “universal” physical substrate, which serves as the operational starting point to assess the causal powers and intrinsic properties of a system within it.

See the theory: Substrate and system.

substrate = pyphi.Substrate(tpm, cm=connectivity_matrix, node_labels=node_labels)
substrate
Substrate3 units · A, B, C
UnitsA, B, C
State spacebinary
Connectivity
ABC
A11·
B·11
C111
TPM
stateABC
(0,0,0)1.00.00.0
(1,0,0)0.01.00.0
(0,1,0)1.01.01.0
(1,1,0)0.01.01.0
(0,0,1)0.00.00.0
(1,0,1)1.01.00.0
(0,1,1)0.00.01.0
(1,1,1)1.00.01.0

The whole analysis in one call#

Before unfolding the analysis one postulate at a time, it is worth seeing the easy path. Given a substrate and a state of interest, a single call to pyphi.analyze runs the entire IIT 4.0 pipeline: it identifies the complex, computes its system integrated information (\(φ_s\)), and unfolds the full cause-effect structure of distinctions and relations that sums to big \(Φ\).

We analyze the substrate in state (1, 0, 0) (A=ON, B=OFF, C=OFF; “Abc” in the paper’s notation, where lowercase letters denote units in the OFF state).

state = (1, 0, 0)

analysis = pyphi.analyze(substrate, state)
analysis
Analysis
Φ3.74674
φs2.0
Distinctions4
Σφd1.79248
Relations10
Σφr1.95426
FormalismIIT_4_0_2023
Distinctions
MechanismφdCause purviewEffect purview
A0.438722Acb
b0.5 Abc
c0.438722bb
Ab0.415037Abcbc
System
UnitsA,B,C
Current state(1, 0, 0)
Specified cause state(0, 0, 0)
Specified effect state(0, 1, 0)
MIP3 parts: {A,B,C}
ii(s)0.0

The resulting Analysis object bundles the whole result together: the System Irreducibility Analysis at analysis.sia, its \(φ_s\) at analysis.phi, and the cause-effect structure at analysis.ces (with analysis.ces.distinctions, analysis.ces.relations, and analysis.ces.big_phi). The rest of Part 1 rebuilds this same result step by step, one IIT postulate at a time.

System Irreducibility Analysis: identifying complexes#

Intrinsicality: Define a candidate system#

Now we instantiate a System object over a candidate set of units, evaluated in the state chosen above. Here the candidate system is the whole substrate, “Abc”. A System is built from a substrate, a state, and a tuple of node indices; any units of the substrate left out of that tuple act as fixed background conditions, and the TPM is conditioned on their state.

See the theory: Substrate and system.

# The candidate system spans all three units of the substrate.
system = pyphi.System(substrate, state, substrate.node_indices)
system
System3 units · A, B, C
UnitsA, B, C
StateA=1, B=0, C=0
Substrate3 units
Connectivity
ABC
A11·
B·11
C111
Cause TPM
stateABC
(0,0,0)1.00.00.0
(1,0,0)0.01.00.0
(0,1,0)1.01.01.0
(1,1,0)0.01.01.0
(0,0,1)0.00.00.0
(1,0,1)1.01.00.0
(0,1,1)0.00.01.0
(1,1,1)1.00.01.0
Effect TPM
stateABC
(0,0,0)1.00.00.0
(1,0,0)0.01.00.0
(0,1,0)1.01.01.0
(1,1,0)0.01.01.0
(0,0,1)0.00.00.0
(1,0,1)1.01.00.0
(0,1,1)0.00.01.0
(1,1,1)1.00.01.0

From the System Irreducibility Analysis (SIA), we can see that the candidate system in state (1, 0, 0) exists (it has both cause and effect power, since \(\textrm{ii}_c > 0\) and \(\textrm{ii}_e > 0\)) in a way that is intrinsic (upon the system Abc itself), informative (it picks out specific previous and next states), and integrated (\(φ_s\) > 0 for the minimum partition).

sia = system.sia()
sia
SystemIrreducibilityAnalysis
φs2.0
Normalized φs0.4
SystemA,B,C
Current state(1, 0, 0)
Cause
Specified state(0, 0, 0)
Intrinsic information3.0
Intrinsic differentiation0.0
Effect
Specified state(0, 1, 0)
Intrinsic information3.0
Intrinsic differentiation0.0
MIP
Partition3 parts: {A,B,C}
Tied MIPs0
ABC
A··✕
B✕·✕
C✕✕·

The minimum partition (MIP) is shown below. It cuts the candidate system into three parts; the ✕ marks indicate the connections that are severed. Note that system partitions are directed, so the matrix may be asymmetric.

See the theory: System integrated information.

sia.partition
DirectedSetPartition
3 parts: {A,B,C}
Severed connections
Connections cut5
ABC
A··✕
B✕·✕
C✕✕·

We can access properties which hold the corresponding system integrated information (\(φ_s\), its irreducibility), and a normalized system integrated information (\(φ_s\) divided by the maximum \(φ_s\) that could be obtained for a system of three nodes).

print(f"φ_s = {sia.phi}")
print(f"φ_s_norm = {sia.normalized_phi}")
φ_s = 2.0
φ_s_norm = 0.4

By the principle of minimal existence, \(φ_s\) must be the minimum between the \(φ\) of the maximally irreducible cause and the maximally irreducible effect within the candidate system itself. For this particular subsystem at the current particular state, cause and effect are equally irreducible.

print(sia.cause.phi)
print(sia.effect.phi)
2.0
2.0

Information: Maximal cause-effect state#

See the theory: System integrated information.

Let’s look more closely at the selected effect state:

sia.effect
RepertoireIrreducibilityAnalysis
φ2.0
Normalized φ0.4
DirectionEFFECT
Mechanism[A,B,C]
Purview[A,B,C]
Specified state(0, 1, 0)
Intrinsic information3.0
Selectivity1.0
Repertoire
Forward probability1.0
Partitioned forward probability0.25
MIP
Partition3 parts: {A,B,C}
Ties
State ties0
Partition ties0

Recall that \(φ_s\) is evaluated for a specific cause or effect state, which is defined as the state that maximizes intrinsic information (\(\textrm{ii}\)). We can inspect this state:

sia.effect.specified_state
Specified EFFECT
DirectionEFFECT
PurviewaBc
Specified state(0, 1, 0)
Intrinsic information3.0

Let’s go deeper into PyPhi’s API to recompute the specified effect state:

maximal_effect_state = system.intrinsic_information(
    direction=pyphi.Direction.EFFECT,
    mechanism=system.node_indices,
    purview=system.node_indices,
    specification_measure=specification_measure,
)

maximal_effect_state
Specified EFFECT
DirectionEFFECT
PurviewaBc
Specified state(0, 1, 0)
Intrinsic information3.0

Integration: System integrated information (\(φ_s\))#

See the theory: System integrated information.

Let’s use PyPhi to recompute sia.effect and \(φ_s\). We will use the fact that we already know the MIP to avoid going through all partitions.

# NOTE: the full set of system partitions may be manually computed by invoking:
system_partitions = pyphi.partition.system_partitions(
    system.node_indices, node_labels=system.node_labels
)
<generator object _directed_set_partitions at 0x10cc9ae30>

We can now compute the integration value with respect to a direction, sia.partition, and the maximal_effect_state we had already obtained.

maximal_cause_effect_states = pyphi.formalism.iit4.system_intrinsic_information(
    system, specification_measure=specification_measure
)

pyphi.formalism.iit4.integration_value(
    pyphi.Direction.EFFECT,
    system,
    sia.partition,
    maximal_cause_effect_states,
    system_measure=system_measure,
)
RepertoireIrreducibilityAnalysis
φ2.0
Normalized φ0.4
DirectionEFFECT
Mechanism[A,B,C]
Purview[A,B,C]
Specified state(0, 1, 0)
Intrinsic information3.0
Selectivity1.0
Repertoire
Forward probability1.0
Partitioned forward probability0.25
MIP
Partition3 parts: {A,B,C}
Ties
State ties0
Partition ties0

Exclusion: Identifying the first complex#

See the theory: System integrated information.

We know the whole Abc is irreducible, but is it maximally irreducible? We will go through all its subsets, computing system irreducibility analyses for all of them.

Indeed, in this case Abc wins over all its subsets (note that in general, the largest subset is not necessarily the maximally irreducible one).

for candidate_nodes in pyphi.utils.powerset(node_labels, nonempty=True):
    node_indices = tuple(
        substrate.node_labels.index(label) for label in candidate_nodes
    )
    try:
        system = pyphi.System(substrate, state, node_indices)
        sia = system.sia()
        print(f"φ_{candidate_nodes} = {sia.phi}")
    except pyphi.exceptions.StateUnreachableError:
        print(f"φ_{candidate_nodes} = 0.0")
φ_('A',) = 1.0
φ_('B',) = 0.0
φ_('C',) = 0.0
φ_('A', 'B') = 0.0
φ_('A', 'C') = 0.0
φ_('B', 'C') = 0.0
φ_('A', 'B', 'C') = 2.0

Composition: Unfolding Φ-structure#

See the theory: Distinctions and relations.

Now that the maximal complex or physical substrate of consciousness has been identified, we can “unfold” the cause-effect structure to examine the compositional structure of the distinctions it specifies and the relations among them.

The maximal complex here is the whole substrate, so we rebuild that System explicitly and keep referring to it as the candidate system.

system = pyphi.System(substrate, state, substrate.node_indices)
System3 units · A, B, C
UnitsA, B, C
StateA=1, B=0, C=0
Substrate3 units
Connectivity
ABC
A11·
B·11
C111
Cause TPM
stateABC
(0,0,0)1.00.00.0
(1,0,0)0.01.00.0
(0,1,0)1.01.01.0
(1,1,0)0.01.01.0
(0,0,1)0.00.00.0
(1,0,1)1.01.00.0
(0,1,1)0.00.01.0
(1,1,1)1.00.01.0
Effect TPM
stateABC
(0,0,0)1.00.00.0
(1,0,0)0.01.00.0
(0,1,0)1.01.01.0
(1,1,0)0.01.01.0
(0,0,1)0.00.00.0
(1,0,1)1.01.00.0
(0,1,1)0.00.01.0
(1,1,1)1.00.01.0

Distinctions#

Distinctions are parts of the complex that specify maximally-irreducible cause and effect states over other parts of the complex. For example, does mechanism “A” specify an irreducible distinction? Yes, it does (it has cause ac and effect B):

mechanism = (0,)

distinction = system.distinction(mechanism)

# NOTE: Mechanism partitions are represented as fractions, with mechanism parts
# in the numerator and purview parts in the denominator.
distinction
Distinction
MechanismA
φd0.438722
Cause
PurviewAc
φ0.5
Specified state(0, 0)
Effect
Purviewb
φ0.438722
Specified state(1,)

Does the higher-order mechanism “Ab” specify an irreducible distinction? It does:

mechanism = (0, 1)

distinction = system.distinction(mechanism)

distinction
Distinction
MechanismAb
φd0.415037
Cause
PurviewAbc
φ0.5
Specified state(0, 0, 0)
Effect
Purviewb
φ0.415037
Specified state(1,)

What about mechanism “Ac”? This mechanism does not specify a distinction, because it is reducible on the cause side:

mechanism = (0, 2)

distinction = system.distinction(mechanism)

distinction
Distinction
MechanismAc
φd0.0
Cause
Purviewbc
φ0.0
Specified state(0, 0)
Effect
Purview∅
φ0.0
Specified stateNone

Relations#

See the theory: Distinctions and relations.

Causal relations capture how the causes and/or effects of a set of distinctions overlap with each other.

We can obtain all 4 irreducible distinctions (mechanisms “A”, “b”, “c”, “Ab”), and then use them to find causal relations among them.

# Unfold all the irreducible distinctions in the complex.
distinctions = system.all_distinctions()
UnresolvedDistinctions
Distinctions4
Σφd1.79248
Distinctions
MechanismφdCause purviewEffect purview
A0.438722Acb
b0.5 Abc
c0.438722bb
Ab0.415037Abcb

NOTE: Before computing relations, it is important to filter out distinctions that are incongruent with the state specified by the entire candidate system (this is done automatically by pyphi.analyze, whose cause-effect structure is discussed below).

distinctions = distinctions.resolve_congruence(sia.system_state)
ResolvedDistinctions
Distinctions4
Σφd1.79248
Distinctions
MechanismφdCause purviewEffect purview
A0.438722Acb
b0.5 Abc
c0.438722bb
Ab0.415037Abcbc

Now we can compute all relations among these distinctions:

relations = pyphi.relations.relations(distinctions)
relations
AnalyticalRelations
Relations10
Σφr1.95426

The output functions like a set object containing all the relations. Each relation in turn also functions like a set that contains the distinctions that are related. Additionally, relations have

  • A relation.phi value.

  • relation.faces: A set of relation faces, each corresponding to an overlap among the purviews of some causes and effects

  • relation.purview: The union of the face purviews (or, equivalently, the intersection of the distinction cause/effect purview unions).

Let’s examine the relation between the first two distinctions.

relation = pyphi.relations.relation(distinctions[:2])
relation
Relation
φr0.292481
Purview[a, c]
Degree2
Faces2

We can look at the relation’s faces:

relation.faces
frozenset({╭─ RelationFace ─╮
           │ Purview   [c]  │
           │ Relata    2    │
           ╰────────────────╯,
           ╭─ RelationFace ─╮
           │ Purview   [a]  │
           │ Relata    2    │
           ╰────────────────╯})

As with collections of relations and relations themselves, a relation face also functions like a set. It contains the causes/effects which have a nonempty congruent overlap among their purviews.

This congruent overlap is stored in the purview attribute:

face = next(iter(relation.faces))
face.purview
{c}

Cause-effect structure and big Φ#

See the theory: The Φ-structure.

Screenshot from 2023-06-20 18-22-07.png

For convenience, PyPhi can fully unfold the cause-effect structure of a system in a single call, performing all the method calls described above. When the system is a maximal complex (as found in the System Irreducibility Analysis above), its cause-effect structure is called a Φ-structure. This is exactly the analysis.ces we obtained from pyphi.analyze at the very start.

ces = pyphi.analyze(substrate, state).ces
ces
CauseEffectStructure
Φ3.74674
φs2.0
Distinctions4
Σφd1.79248
Relations10
Σφr1.95426
Distinctions
MechanismφdCause purviewEffect purview
A0.438722Acb
b0.5 Abc
c0.438722bb
Ab0.415037Abcbc

Individual properties and components of the structure remain accessible:

# φ_s
print(f"φ_s = {sia.phi}")

# Big Φ (sum of distinctions' and relations' small φ)
print(f"  Φ = {ces.big_phi}")
φ_s = 2.0
  Φ = 3.746741665224354
ces.distinctions
ResolvedDistinctions
Distinctions4
Σφd1.79248
Distinctions
MechanismφdCause purviewEffect purview
A0.438722Acb
b0.5 Abc
c0.438722bb
Ab0.415037Abcbc
ces.relations
AnalyticalRelations
Relations10
Σφr1.95426

Reproducing figures 1, 2 and 4#

The following sections are intended to reinforce and clarify certain aspects of the analysis by delving deeper into the algorithmic computation of distinctions and relations. For this we will use the nondeterministic substrate employed in Figure 1, Figure 2 and Figure 4 in the main IIT 4.0 text, a small recurrent network with both excitation and inhibition, analyzed using PyPhi to reproduce the results shown there.

See the theory: What IIT 4.0 computes.

We start by defining the substrate and the state of interest:

k = 4

weights = np.array(
    [
        [-.2, 0.7, 0.2],
        [0.7, -.2, 0.0],
        [0.0, -.8, 0.2]
    ]
)

node_labels = ["A", "B", "C"]

substrate = pyphi.substrate_generator.build_substrate(
    "ising",
    weights,
    node_labels=node_labels,
    temperature=1 / k,
)

state = (0, 1, 1)
(0, 1, 1)

Figure 1: Identifying complexes#

See the theory: System integrated information.

Screenshot from 2023-06-28 16-47-41.png

Let’s jump straight into panel (E) in Fig 1, by performing a combinatorial search over all possible candidate subsystems, applying exclusion to find the first maximally-irreducible complex, then repeating the procedure with the remaining units to find the second maximally-irreducible complex and so on.

As shown in Fig 1, the substrate aBC condenses into complexes C and aB:

# System Irreducibility Analyses
sias = []

for candidate_nodes in pyphi.utils.powerset(node_labels, nonempty=True):
    node_indices = tuple(
        substrate.node_labels.index(label) for label in candidate_nodes
    )
    try:
        system = pyphi.System(substrate, state, node_indices)
        sias.append(system.sia())
    except pyphi.exceptions.StateUnreachableError:
        pass

sias = sorted(sias, key=lambda sia: sia.phi, reverse=True)
print(sias)
[╭─ SystemIrreducibilityAnalysis ───────╮
│ φ_s                         0.21222  │
│ Normalized φ_s              0.21222  │
│ System                      C        │
│ Current state               (1,)     │
├─ Cause ──────────────────────────────┤
│ Specified state             (1,)     │
│ Intrinsic information       0.21222  │
│ Intrinsic differentiation   0.663793 │
├─ Effect ─────────────────────────────┤
│ Specified state             (1,)     │
│ Intrinsic information       0.29106  │
│ Intrinsic differentiation   1.0      │
├─ MIP ────────────────────────────────┤
│ Partition                   Total    │
│ Tied MIPs                   0        │
│     C                                │
│ C   ✕                                │
╰──────────────────────────────────────╯, ╭─ SystemIrreducibilityAnalysis ─────────────╮
│ φ_s                         0.171863       │
│ Normalized φ_s              0.171863       │
│ System                      A,B            │
│ Current state               (0, 1)         │
├─ Cause ────────────────────────────────────┤
│ Specified state             (1, 0)         │
│ Intrinsic information       0.843228       │
│ Intrinsic differentiation   0.663964       │
├─ Effect ───────────────────────────────────┤
│ Specified state             (1, 0)         │
│ Intrinsic information       1.09763        │
│ Intrinsic differentiation   0.0404968      │
├─ MIP ──────────────────────────────────────┤
│ Partition                   2 parts: {A,B} │
│ Tied MIPs                   0              │
│     A   B                                  │
│ A   ·   ✕                                  │
│ B   ·   ·                                  │
╰────────────────────────────────────────────╯, ╭─ SystemIrreducibilityAnalysis ──────────────╮
│ φ_s                         0.133873        │
│ Normalized φ_s              0.0669366       │
│ System                      A,B,C           │
│ Current state               (0, 1, 1)       │
├─ Cause ─────────────────────────────────────┤
│ Specified state             (1, 0, 0)       │
│ Intrinsic information       0.718749        │
│ Intrinsic differentiation   1.26848         │
├─ Effect ────────────────────────────────────┤
│ Specified state             (1, 0, 0)       │
│ Intrinsic information       0.841796        │
│ Intrinsic differentiation   1.0405          │
├─ MIP ───────────────────────────────────────┤
│ Partition                   2 parts: {AB,C} │
│ Tied MIPs                   0               │
│     A   B   C                               │
│ A   ·   ·   ·                               │
│ B   ·   ·   ·                               │
│ C   ✕   ✕   ·                               │
╰─────────────────────────────────────────────╯, ╭─ SystemIrreducibilityAnalysis ────────╮
│ φ_s                         0.039591  │
│ Normalized φ_s              0.039591  │
│ System                      A         │
│ Current state               (0,)      │
├─ Cause ───────────────────────────────┤
│ Specified state             (1,)      │
│ Intrinsic information       0.039591  │
│ Intrinsic differentiation   0.924838  │
├─ Effect ──────────────────────────────┤
│ Specified state             (1,)      │
│ Intrinsic information       0.0684421 │
│ Intrinsic differentiation   0.0388909 │
├─ MIP ─────────────────────────────────┤
│ Partition                   Total     │
│ Tied MIPs                   0         │
│     A                                 │
│ A   ✕                                 │
╰───────────────────────────────────────╯, ╭─ SystemIrreducibilityAnalysis ─────────╮
│ φ_s                         0.00315846 │
│ Normalized φ_s              0.00315846 │
│ System                      B          │
│ Current state               (1,)       │
├─ Cause ────────────────────────────────┤
│ Specified state             (0,)       │
│ Intrinsic information       0.108312   │
│ Intrinsic differentiation   0.810094   │
├─ Effect ───────────────────────────────┤
│ Specified state             (0,)       │
│ Intrinsic information       0.00315846 │
│ Intrinsic differentiation   0.00160594 │
├─ MIP ──────────────────────────────────┤
│ Partition                   Total      │
│ Tied MIPs                   0          │
│     B                                  │
│ B   ✕                                  │
╰────────────────────────────────────────╯, ╭─ NullSystemIrreducibilityAnalysis ──────╮
│ φ_s              0.0                    │
│ Normalized φ_s   0.0                    │
│ System           A,C                    │
│ Current state    None                   │
├─ MIP ───────────────────────────────────┤
│ Partition        NullCut((0, 2))        │
│ Tied MIPs        0                      │
├─ Reasons ───────────────────────────────┤
│                  NO_STRONG_CONNECTIVITY │
╰─────────────────────────────────────────╯, ╭─ NullSystemIrreducibilityAnalysis ──────╮
│ φ_s              0.0                    │
│ Normalized φ_s   0.0                    │
│ System           B,C                    │
│ Current state    None                   │
├─ MIP ───────────────────────────────────┤
│ Partition        NullCut((1, 2))        │
│ Tied MIPs        0                      │
├─ Reasons ───────────────────────────────┤
│                  NO_STRONG_CONNECTIVITY │
╰─────────────────────────────────────────╯]

Figure 2: Distinctions#

See the theory: Distinctions and relations.

Screenshot from 2023-06-28 16-51-05.png

We now want to derive all the irreducible distinctions in complex aB, both first-order and higher-order together with their \(φ_d\) values. A more detailed derivation with intermediate steps (intrinsic information, MIP, maximal cause/effect states) is developed in later sections.

# Select the System Irreducibility Analysis corresponding to complex aB:
sia = sias[1]
nodes = sia.node_indices  # Same as nodes = (0, 1)

# Obtain the system.
system = pyphi.System(substrate, state, nodes)

# Unfold all the irreducible distinctions in complex aB.
distinctions = system.all_distinctions()

# Discard potential distinctions which are incongruent with the cause and
# effect specified by the complex as a whole.
distinctions = distinctions.resolve_congruence(sia.system_state)

print(distinctions)
╭─ ResolvedDistinctions ─────────────────────────────────╮
│ Distinctions   3                                       │
│ Σφ_d           0.727763                                │
├─ Distinctions ─────────────────────────────────────────┤
│ Mechanism   φ_d         Cause purview   Effect purview │
│ a           0.332728    B               B              │
│ B           0.323594    a               aB             │
│ aB          0.0714404   B               aB             │
╰────────────────────────────────────────────────────────╯

A more detailed derivation#

# Change this to explore different mechanisms.
mechanism = (0,1)
(0, 1)

Intrinsic information (\(\textrm{ii}\)) and the specified cause/effect state.#

DIRECTION = pyphi.Direction.CAUSE
SYSTEM = system

# Explore all cause purviews.
purviews = SYSTEM.potential_purviews(DIRECTION, mechanism)

for purview in purviews:
    # Find specified state for this particular purview: the state for which
    # intrinsic information is maximum.
    specified_states = SYSTEM.intrinsic_information(
        DIRECTION, mechanism, purview,
        specification_measure=specification_measure,
    ).ties

    print(specified_states)
(╭─ Specified CAUSE ────────────────╮
│ Direction               CAUSE    │
│ Purview                 Ab       │
│ Specified state         (1, 0)   │
│ Intrinsic information   0.843228 │
╰──────────────────────────────────╯,)
(╭─ Specified CAUSE ────────────────╮
│ Direction               CAUSE    │
│ Purview                 b        │
│ Specified state         (0,)     │
│ Intrinsic information   0.873686 │
╰──────────────────────────────────╯,)
(╭─ Specified CAUSE ────────────────╮
│ Direction               CAUSE    │
│ Purview                 A        │
│ Specified state         (1,)     │
│ Intrinsic information   0.397981 │
╰──────────────────────────────────╯,)

Similarly for the effect side:

DIRECTION = pyphi.Direction.EFFECT
SYSTEM = system

# Explore all effect purviews.
purviews = SYSTEM.potential_purviews(DIRECTION, mechanism)

for purview in purviews:
    # Find specified state for this particular purview: the state for which
    # intrinsic information is maximum.
    specified_states = SYSTEM.intrinsic_information(
        DIRECTION, mechanism, purview,
        specification_measure=specification_measure,
    ).ties

    print(specified_states)
(╭─ Specified EFFECT ──────────────╮
│ Direction               EFFECT  │
│ Purview                 Ab      │
│ Specified state         (1, 0)  │
│ Intrinsic information   1.09763 │
╰─────────────────────────────────╯,)
(╭─ Specified EFFECT ───────────────╮
│ Direction               EFFECT   │
│ Purview                 b        │
│ Specified state         (0,)     │
│ Intrinsic information   0.336617 │
╰──────────────────────────────────╯,)
(╭─ Specified EFFECT ───────────────╮
│ Direction               EFFECT   │
│ Purview                 A        │
│ Specified state         (1,)     │
│ Intrinsic information   0.935547 │
╰──────────────────────────────────╯,)

Minimum partition (MIP) and integrated information (\(\varphi\))#

DIRECTION = pyphi.Direction.CAUSE
SYSTEM = system

# Explore all cause purviews.
purviews = SYSTEM.potential_purviews(DIRECTION, mechanism)

cause_mips = []

for purview in purviews:
    # Explore all mechanism partitions for this particular purview and find MIP:
    # the partition for which integrated information is minimum.

    # NOTE: this call internally recomputes and uses the specified state.
    mip = SYSTEM.find_mip(DIRECTION, mechanism, purview)

    print(mip)
    cause_mips.append(mip)
╭─ RepertoireIrreducibilityAnalysis ────────────────╮
│ φ                                 0.138809        │
│ Normalized φ                      0.0694043       │
│ Direction                         CAUSE           │
│ Mechanism                         [A,B]           │
│ Purview                           [A,B]           │
│ Specified state                   (1, 0)          │
│ Intrinsic information             0.843228        │
│ Selectivity                       0.631142        │
├─ Repertoire ──────────────────────────────────────┤
│ Forward probability               0.802601        │
│ Partitioned forward probability   0.689118        │
├─ MIP ─────────────────────────────────────────────┤
│ Partition                         A/B × B/A × ∅/∅ │
├─ Ties ────────────────────────────────────────────┤
│ State ties                        0               │
│ Partition ties                    0               │
╰───────────────────────────────────────────────────╯
╭─ RepertoireIrreducibilityAnalysis ────────────────╮
│ φ                                 0.217943        │
│ Normalized φ                      0.217943        │
│ Direction                         CAUSE           │
│ Mechanism                         [A,B]           │
│ Purview                           [B]             │
│ Specified state                   (0,)            │
│ Intrinsic information             0.873686        │
│ Selectivity                       0.947459        │
├─ Repertoire ──────────────────────────────────────┤
│ Forward probability               0.58436         │
│ Partitioned forward probability   0.498236        │
├─ MIP ─────────────────────────────────────────────┤
│ Partition                         A/B × B/∅ × ∅/∅ │
├─ Ties ────────────────────────────────────────────┤
│ State ties                        0               │
│ Partition ties                    0               │
╰───────────────────────────────────────────────────╯
╭─ RepertoireIrreducibilityAnalysis ────────────────╮
│ φ                                 0.0932374       │
│ Normalized φ                      0.0932374       │
│ Direction                         CAUSE           │
│ Mechanism                         [A,B]           │
│ Purview                           [A]             │
│ Specified state                   (1,)            │
│ Intrinsic information             0.397981        │
│ Selectivity                       0.729711        │
├─ Repertoire ──────────────────────────────────────┤
│ Forward probability               0.406069        │
│ Partitioned forward probability   0.371652        │
├─ MIP ─────────────────────────────────────────────┤
│ Partition                         A/∅ × B/A × ∅/∅ │
├─ Ties ────────────────────────────────────────────┤
│ State ties                        0               │
│ Partition ties                    0               │
╰───────────────────────────────────────────────────╯

Similarly for the effect side:

DIRECTION = pyphi.Direction.EFFECT
SYSTEM = system

# Explore all effect purviews.
purviews = SYSTEM.potential_purviews(DIRECTION, mechanism)

effect_mips = []

for purview in purviews:
    # Explore all mechanism partitions for this particular purview and find MIP:
    # the partition for which integrated information is minimum.

    # NOTE: this call internally recomputes and uses the specified state.
    mip = SYSTEM.find_mip(DIRECTION, mechanism, purview)

    print(mip)
    effect_mips.append(mip)
╭─ RepertoireIrreducibilityAnalysis ────────────────╮
│ φ                                 0.0714404       │
│ Normalized φ                      0.0357202       │
│ Direction                         EFFECT          │
│ Mechanism                         [A,B]           │
│ Purview                           [A,B]           │
│ Specified state                   (1, 0)          │
│ Intrinsic information             1.09763         │
│ Selectivity                       0.97232         │
├─ Repertoire ──────────────────────────────────────┤
│ Forward probability               0.97232         │
│ Partitioned forward probability   0.924041        │
├─ MIP ─────────────────────────────────────────────┤
│ Partition                         A/B × B/A × ∅/∅ │
├─ Ties ────────────────────────────────────────────┤
│ State ties                        0               │
│ Partition ties                    0               │
╰───────────────────────────────────────────────────╯
╭─ RepertoireIrreducibilityAnalysis ────────────────╮
│ φ                                 0.00315846      │
│ Normalized φ                      0.00315846      │
│ Direction                         EFFECT          │
│ Mechanism                         [A,B]           │
│ Purview                           [B]             │
│ Specified state                   (0,)            │
│ Intrinsic information             0.336617        │
│ Selectivity                       0.998887        │
├─ Repertoire ──────────────────────────────────────┤
│ Forward probability               0.998887        │
│ Partitioned forward probability   0.996701        │
├─ MIP ─────────────────────────────────────────────┤
│ Partition                         A/B × B/∅ × ∅/∅ │
├─ Ties ────────────────────────────────────────────┤
│ State ties                        0               │
│ Partition ties                    0               │
╰───────────────────────────────────────────────────╯
╭─ RepertoireIrreducibilityAnalysis ────────────────╮
│ φ                                 0.0684421       │
│ Normalized φ                      0.0684421       │
│ Direction                         EFFECT          │
│ Mechanism                         [A,B]           │
│ Purview                           [A]             │
│ Specified state                   (1,)            │
│ Intrinsic information             0.935547        │
│ Selectivity                       0.973403        │
├─ Repertoire ──────────────────────────────────────┤
│ Forward probability               0.973403        │
│ Partitioned forward probability   0.9271          │
├─ MIP ─────────────────────────────────────────────┤
│ Partition                         A/∅ × B/A × ∅/∅ │
├─ Ties ────────────────────────────────────────────┤
│ State ties                        0               │
│ Partition ties                    0               │
╰───────────────────────────────────────────────────╯

Maximal cause/effect purviews and \(φ_d\)#

Finally, select the maximal cause and maximal effect purviews for this mechanism. Remember the distinction’s irreducibility (\(φ_d\)) will be the minimum of the two.

# Find maximal cause and effect.
print(max(cause_mips))
print(max(effect_mips))
╭─ RepertoireIrreducibilityAnalysis ────────────────╮
│ φ                                 0.217943        │
│ Normalized φ                      0.217943        │
│ Direction                         CAUSE           │
│ Mechanism                         [A,B]           │
│ Purview                           [B]             │
│ Specified state                   (0,)            │
│ Intrinsic information             0.873686        │
│ Selectivity                       0.947459        │
├─ Repertoire ──────────────────────────────────────┤
│ Forward probability               0.58436         │
│ Partitioned forward probability   0.498236        │
├─ MIP ─────────────────────────────────────────────┤
│ Partition                         A/B × B/∅ × ∅/∅ │
├─ Ties ────────────────────────────────────────────┤
│ State ties                        0               │
│ Partition ties                    0               │
╰───────────────────────────────────────────────────╯
╭─ RepertoireIrreducibilityAnalysis ────────────────╮
│ φ                                 0.0714404       │
│ Normalized φ                      0.0357202       │
│ Direction                         EFFECT          │
│ Mechanism                         [A,B]           │
│ Purview                           [A,B]           │
│ Specified state                   (1, 0)          │
│ Intrinsic information             1.09763         │
│ Selectivity                       0.97232         │
├─ Repertoire ──────────────────────────────────────┤
│ Forward probability               0.97232         │
│ Partitioned forward probability   0.924041        │
├─ MIP ─────────────────────────────────────────────┤
│ Partition                         A/B × B/A × ∅/∅ │
├─ Ties ────────────────────────────────────────────┤
│ State ties                        0               │
│ Partition ties                    0               │
╰───────────────────────────────────────────────────╯

Figure 4: Relations#

See the theory: Distinctions and relations.

Figure 4

All \(2^{3} - 1\) relations among distinctions a, B and AB exist.

As in Fig 4, we will focus on the first-order relation {a, aB}, with overlap over purview b and \(φ_r\) = 0.035 By default the relation set is a closed-form summary; individual relations are enumerated explicitly with materialize():

relations = pyphi.relations.relations(distinctions).materialize()
print(f"Total number of relations: {len(relations)}\n")

# Filter out relations other than the one between {aB, a}
a_aB_relation = [
    relation for relation in relations if (relation.mechanisms == {(0, 1), (0,)})
]

print(a_aB_relation)
Total number of relations: 7

[╭─ Relation ──────────╮
│ φ_r       0.0357202 │
│ Purview   [b]       │
│ Degree    2         │
│ Faces     9         │
╰─────────────────────╯]

A more detailed derivation#

Computing a specific relation#

We start by selecting the relevant distinctions:

# Assuming a certain order, we can slice the object with all distinctions to
# only include first (a) and third (aB) ones.
distinctions_a_aB = distinctions[::2]
distinctions_a_aB
ResolvedDistinctions
Distinctions2
Σφd0.404169
Distinctions
MechanismφdCause purviewEffect purview
a0.332728 BB
aB0.0714404BaB

From the relevant distinctions, PyPhi then computes the combinations of size greater than 2 that share a congruent purview overlap.

Since we are dealing with only two distinctions, there’s only one such combination of distinctions: the pair {a, aB} itself.

# Materialize the combinations so they can be iterated more than once below
# (the underlying helper returns a one-shot generator).
combinations = list(
    pyphi.relations._combinations_with_nonempty_congruent_overlap(
        distinctions_a_aB,
        min_degree=2,
        max_degree=None,
    )
)

combinations
[frozenset({0, 1})]

We are ready to reconstruct the relation by calling pyphi.relations.Relation:

for combination in combinations:
  relation = pyphi.relations.Relation((distinctions_a_aB[i] for i in combination))
  print(relation)
╭─ Relation ──────────╮
│ φ_r       0.0357202 │
│ Purview   [b]       │
│ Degree    2         │
│ Faces     9         │
╰─────────────────────╯

Computing \(φ_r\)#

Then, the relation’s irreducibility value (\(φ_r\)) is defined as the \(φ_d\)-per-unit ratio for the distinction (relatum) with the minimum such value (distinction_phi_per_unique_purview_unit),

\[ \min_{d ∈ 𝐝} \frac{φ_d}{|z^*_c(d)\cup z^*_e(d)|} \]

weighted by the size of the overlap (len(relation.purview)),

\[ \left|\bigcup_{f ∈ 𝒇(𝐝)} \; o^*_f \;\right| \]
distinction_phi_per_unique_purview_unit = [
    relatum.phi / len(relatum.purview_union) for relatum in relation
]

phi_r = len(relation.purview) * min(distinction_phi_per_unique_purview_unit)

print(f"φ_r = {phi_r}")
φ_r = 0.03572021119668863

What next#

An Analysis carries everything computed above. Two common next steps are saving a cause-effect structure for later and exporting it to a pandas DataFrame for inspection or plotting.

# Rebuild the Part 1 substrate (the `tpm` and `connectivity_matrix` from the
# start of the notebook are still in scope) and analyze it.
substrate_abc = pyphi.Substrate(
    tpm, cm=connectivity_matrix, node_labels=("A", "B", "C")
)
analysis = pyphi.analyze(substrate_abc, (1, 0, 0))

# Save the cause-effect structure to JSON, then load it back.
# (Save `analysis.ces`, not the `Analysis` wrapper.)
pyphi.save(analysis.ces, "ces.json")
reloaded_ces = pyphi.load("ces.json")

# Export the distinctions to a pandas DataFrame.
analysis.ces.to_pandas()
phi mechanism_state cause_purview cause_state effect_purview effect_state
mechanism
(A,) 0.438722 (1,) (A, C) (0, 0) (B,) (1,)
(B,) 0.500000 (0,) (A, B) (0, 0) (C,) (0,)
(C,) 0.438722 (0,) (B,) (0,) (B,) (1,)
(A, B) 0.415037 (1, 0) (A, B, C) (0, 0, 0) (B, C) (1, 0)

For more, see the how-to guides:

PyPhi documentation#

See pyphi.readthedocs.io for further information on PyPhi usage and its API.