Computational complexity#

Computing integrated information is combinatorially expensive: it searches over subsets, purviews, and partitions of a system, and the number of each grows exponentially or superexponentially with the number of units \(n\). This page has two aims: to give a sense of what each stage costs, and to lay out the options for reducing it by configuring PyPhi to use heuristics. The page focuses on IIT 4.0; actual causation and the earlier IIT 3.0 are covered more briefly at the end.

Formalism

Stage

Dominant cost

Practical ceiling

IIT 4.0

distinctions (CES)

\(\gtrsim 2^n\) mechanisms, super-exponential per pair

~6–8 units

IIT 4.0

relations

up to \(2^{\,2^n-1}-1\)

~6–8 units

IIT 4.0

system \(\varphi_s\)

\(B_n(3)\) directed set partitions

~10–12 units

Actual causation

account

\(2^n\) mechanisms × \(2^n\) purviews × set partitions

~8–10 units

IIT 3.0

CES / subsystem Φ / major complex

\(O(n^5\,3^n)\) / \(6^n\) / \(7^n\)

~10–12 units

The single most expensive term anywhere in IIT is the 4.0 relation count, \(2^{\,2^n-1}-1\) (doubly exponential).

The inner kernel: one repertoire#

The innermost operation builds a repertoire — a probability distribution over the states of a purview — and measures a distance between two of them. A repertoire over a purview of \(p\) units, in a substrate of alphabet size \(k\), is an array of \(k^p\) numbers. PyPhi builds it as a product of per-unit factors over a factored transition-probability matrix (pyphi.core.repertoire_algebra), so a mechanism of \(m\) units costs \(O(m\,k^p)\) multiplications, and the results are memoized so repeated mechanism–purview pairs across the partition sweep are free. IIT 4.0’s intrinsic-difference measures read the distribution in a single pass, \(O(k^p)\). (IIT 3.0 instead uses the earth mover’s distance: \(O(n^2\,3^n)\) in general, or \(O(n)\) for effect repertoires under conditional independence — Mayner et al. 2018.)

The cost of IIT 4.0#

IIT 4.0 computes a cause–effect structure — its distinctions and the relations among them — and, at the system level, the system integrated information \(\varphi_s\). These are three separate costs.

Distinctions reuse the mechanism × purview loop: \(2^n - 1\) mechanisms, up to \(2^n - 1\) cause and effect purviews each (pruned by the connectivity matrix), and the mechanism partitions of each pair. The default scheme is JOINT_PARTITION_ALL, which enumerates all set partitions of the mechanism and purview rather than only bipartitions — a Bell-number-weighted count per pair, super-exponential in \(m+p\) and far more than 3.0’s \(2^{\,m+p-1}\). At the sizes actually reachable, the distinctions often dominate the cost, precisely because of this scheme.

Relations are the asymptotically dominant term in all of IIT. A relation binds a set of distinctions that share a congruent purview overlap; over \(n\) units the number of possible relations is doubly exponential (Zaeemzadeh & Tononi, 2024, Sec 2.2):

\[ |R| = 2^{\,2^n - 1} - 1. \]

The counts are computed exactly by pyphi.formalism.iit4.bounds:

import pyphi
from pyphi.formalism.iit4 import bounds

rows = [
    {
        "n": n,
        "possible distinctions (2**n - 1)": bounds.number_of_possible_distinctions(n),
        "possible relations (2**(2**n - 1) - 1)": bounds.number_of_possible_relations(n),
    }
    for n in range(1, 7)
]

import pandas as pd
pd.DataFrame(rows).set_index("n")
possible distinctions (2**n - 1) possible relations (2**(2**n - 1) - 1)
n
1 1 1
2 3 7
3 7 127
4 15 32767
5 31 2147483647
6 63 9223372036854775807

By default, relation_computation = "ANALYTICAL" computes the relation count and summed φ in closed form by inclusion–exclusion, without enumerating individual relations at all. Setting relation_computation = "CONCRETE" enumerates them explicitly, but not by walking all \(2^D\) subsets of the \(D\) distinctions found: it walks them depth-first and prunes a whole subtree the moment the running purview overlap becomes empty (pyphi.combinatorics.combinations_with_nonempty_intersection), so the realized count is the number of subsets with nonempty congruent overlap — worst case \(2^D - D - 1\), but typically far fewer. Each candidate relation is lazy: its φ and faces are computed only when read.

System \(\varphi_s\) is separate and much cheaper: it sweeps the DIRECTED_SET_PARTITION system cuts — \(B_n(3)\) before de-duplication — evaluating the whole system at each, with no inner mechanism loop.

The intrinsic-information term of \(\varphi_s\) (Mayner, Marshall & Tononi, 2026, Eq. 23) is evaluated once, at the already-selected minimum-information partition, an \(O(1)\) step that does not change the number of partitions swept; shortcircuit_sia is a constant-factor pre-check that returns early when the system has no cause or effect.

The published φ upper bounds — as opposed to the counts — are also codified, with citations, in pyphi.formalism.iit4.bounds: distinction φ is at most \(|M|\,|Z|\) (Theorem 1), system \(\varphi_s\) at most \(n(n-1)\) (Table 2), the sum of distinction φ grows as \(\approx \tfrac{n^2}{2}2^n\) (Eq. 6), and the sum of relation φ grows hyper-exponentially, \(O(n^2\,2^{\,2^n})\) (Zaeemzadeh & Tononi, 2024). Alongside these worst-case, size-based ceilings, the same module provides measured certificates: given a computed distinction set, sum_phi_relations_measured_bound() evaluates the paper’s linear-program maximum on the measured per-atom profile — a certified bound on the sum of relation φ that is typically orders of magnitude tighter than the worst-case ceiling — and big_phi_measured_bound() adds the exact distinction-φ sum to give a certified ceiling on Φ.

How it scales in practice#

benchmarks/complexity/scaling.py times each stage on a family of stochastic-majority ring systems of growing size. Each unit’s next state is a logistic function of the summed spins of its two ring neighbours and itself; the construction is deterministic in \((n, \beta)\), so the systems reproduce exactly. For each size it records several timing trials, saves the raw values, and fits \(\log(\text{time}) = a + b\,n\), whose slope gives the per-unit growth factor \(e^b\).

Note

The timing runs are precomputed, not executed at documentation-build time. Reproduce them with uv run python benchmarks/complexity/scaling.py; the raw timings, aggregates, fitted rates, and figure are written to benchmarks/complexity/results/.

Log-scale wall-clock runtime versus system size for each stage.

Median wall-clock runtime versus system size \(n\), one curve per stage, on a logarithmic vertical axis. A straight line indicates exponential growth; the upward-bending IIT 4.0 cause–effect-structure curve is super-exponential. IIT 3.0 is shown for comparison.#

The IIT 4.0 cause–effect structure grows fastest of all, and not at a fixed base: it is dominated by relations, whose realized count explodes far faster than the number of distinctions.

\(n\)

distinctions

relations

2

3

5

3

7

127

4

15

6 879

5

31

1 413 375

The fitted growth factors (over \(n \ge 3\), where fixed overhead no longer dominates) are below:

Stage

raw base \(e^b\)

base after dividing out \(n^5\)

\(R^2\)

IIT 4.0 — CES

28.1

7.8

0.993

IIT 4.0 — \(\varphi_s\)

7.9

2.8

0.999

Connectivity matters as much as size#

The growth factors above are specific to the ring family used for the measurements, and they are best read as a single point in a space parameterized as much by a system’s connectivity as by its size. For a fixed number of units \(n\), the sparsity of the connectivity matrix governs the practical cost through several distinct mechanisms.

The most consequential is purview pruning. A mechanism can constrain only those purviews it reaches through the connectivity matrix, so in a sparsely connected system the number of candidate purviews evaluated per mechanism falls well below \(2^n\). Because the surviving purviews are also smaller, the repertoires and distances computed over them are defined on distributions of correspondingly reduced support (\(k^p\) with \(p \ll n\)); as this per-operation cost enters the exponential base rather than a leading constant, connectivity influences the rate of growth and not merely its scale. Missing connections save work a second way: when they imply that a mechanism’s repertoire factorizes over a purview, the mechanism is reducible over that purview a priori and need not be evaluated at all (Mayner et al., 2018).

Two further reductions act at the system level. A subsystem that is not strongly connected has \(\varphi_s = 0\) by construction and is excluded from the search for the maximal complex, so the measured major-complex cost lies below its \(7^n\) worst case. And because relations are supported on the congruent overlaps of distinction purviews, the smaller and less overlapping purviews of a sparse system yield far fewer realized relations than the \(2^{\,2^n-1}-1\) worst case.

These effects bound the realized cost, not the asymptotic worst case, which is attained at complete connectivity and is unchanged. This qualification matters in practice: integration, the quantity IIT is designed to measure, works against sparsity. The systems of greatest scientific interest tend to be densely connected and therefore costly, while a system sparse enough to fall apart into independent parts has \(\varphi_s = 0\) anyway. Connectivity determines the practical ceiling at least as much as unit count does.

Estimating a workload before running it#

Every count above is knowable before any φ is computed. pyphi.estimate_analysis walks the same enumeration machinery the analysis would use — the active system partition scheme, the connectivity-pruned purview sets, the mechanism partitions per (mechanism, purview) size pair — and returns the counts as an AnalysisEstimate, without evaluating anything:

import pyphi
from pyphi import examples

pyphi.estimate_analysis(examples.basic_substrate())
AnalysisEstimate3 units, full
Units3
State space8
System partitions= 22
Specified-state evaluations16
Mechanisms7
Purview evaluations= 30
Mechanism partition sweeps= 438
Relationsclosed form
Possible distinctions7
Possible relations127
CappedFalse

The estimate reports counts and structural weights (the state-space size is the per-evaluation cost scale); it never predicts wall time, which is machine- and configuration-dependent. It computes no φ, but its counting walk is itself work: on ten fully connected units it takes tens of seconds, and it stops at its limit budget with capped=True, reporting lower bounds; see Estimate the cost before you run for raising the budget. The counterpart for grain searches is SearchBounds.estimate, described in the next section.

Reducing the cost#

Several options change how much of the search PyPhi actually performs. They fall into three kinds, and the distinction matters for how a result should be read:

  • Exact reformulations compute the same answer with less work.

  • Approximations trade exactness for speed and return a bound or an estimate.

  • Formalism choices change which quantity is computed. Their costs are not comparable as speedups — a different scheme is a different definition, not a faster route to the same number.

Option

Setting

Kind

Effect on cost

relation_computation

ANALYTICAL (default); set CONCRETE to enumerate

exact reformulation (yields the count and summed φ, not individual relations)

removes the \(2^D\) relation enumeration; the CES then scales like its distinctions alone

mechanism_partition_scheme

JOINT_PARTITION_ALL / WEDGE_TRIPARTITION / JOINT_BIPARTITION

formalism choice

per-(mechanism, purview) partition count Bell-weighted \(> 2^{m-1}3^p > 2^{m+p-1}\)

prune (grain search)

"certified" (default); "off" evaluates everything

exact reformulation (identical complexes, ties, and verdicts; skipped candidates report their ii ceiling)

skips candidate partition sweeps certified below an overlapping accepted complex by the requirement; saves most when mapped variants dominate the candidate set; when unit-derivation evaluations dominate, the cost is unchanged

shortcircuit_sia

True

exact early-exit

returns before the sweep when a system has no cause or effect; constant factor

shortcircuit_distinctions

True

exact early-exit

skips a distinction’s remaining search for its maximally irreducible cause and effect (MICE) once one direction is found reducible; on reducible mechanisms this saves an entire purview sweep

parallel

False → True

exact

constant factor set by the number of cores

system_partition_scheme (3.0)

DIRECTED_BIPARTITION → …_CUT_ONE

approximation (upper bound on Φ)

system cuts \(2^n \to 2n\)

assume_partitions_cannot_create_new_concepts (3.0)

False → True

approximation (no guaranteed bound)

reuses the unpartitioned distinctions across cuts

Measured on the same ring family (benchmarks/complexity/options.py):

Runtime versus system size for each configuration option, three panels.

Median runtime versus \(n\) for each option, logarithmic vertical axis. Left: the mechanism partition scheme separates the curves the most — it has the strongest effect on IIT 4.0 distinction cost. Middle: analytical and concrete relations nearly coincide for this system. Right: the IIT 3.0 cut-one approximation is shallower and reaches one unit further than the full cut sweep.#

Option

Setting

Median at \(n=5\)

Largest \(n\) under a 45 s/eval budget

mechanism scheme

JOINT_BIPARTITION

3.3 s

7

WEDGE_TRIPARTITION

8.8 s

6

JOINT_PARTITION_ALL (default)

48 s

5

relations

ANALYTICAL (default)

41 s

5

CONCRETE

50 s

5

system cuts (3.0)

cut-one (\(2n\))

22 s

6

full (\(2^n\), default)

56 s

5

Reading the table, one option at a time:

  • The mechanism partition scheme has the largest effect on IIT 4.0 distinction cost. At \(n=5\) the default JOINT_PARTITION_ALL is about 15× slower than JOINT_BIPARTITION, and the gap widens with \(n\): JOINT_BIPARTITION reaches \(n=7\) in ~4 minutes while JOINT_PARTITION_ALL is already at ~48 s by \(n=5\). But this is a formalism choice — the schemes compute different partition families and therefore different φ values, so the cheaper one is a different definition, not a faster route to the same answer.

  • Analytical relations help only modestly here, ~1.2× at \(n=5\), because for this system the cause–effect structure cost is dominated by its distinctions, not its relations: the relation term that ANALYTICAL eliminates is not the bottleneck at reachable sizes. Without a per-evaluation time budget, IIT 4.0 CES at \(n=6\) takes about 30 minutes with analytical relations, nearly all of it in the distinctions. On a system with a large, densely overlapping set of distinctions the relation term dominates instead, and the closed form is the difference between tractable and not.

  • Cut-one is the most effective approximation for IIT 3.0, ~2.6× at \(n=5\), and it reaches \(n=6\) where the full sweep does not, because it replaces the \(2^n\) system cuts with \(2n\). It returns an upper bound on Φ rather than the exact value.

No single approximation makes IIT 4.0 tractable at larger \(n\): the distinction cost (set by the partition scheme) and the relation cost (set by relation_computation) are separate terms, and reaching higher \(n\) means lowering both.

Stacking settings for working with larger networks#

The gains compound. Stacking the compatible cost-reducing settings — rather than any one alone — is what moves the ceiling.

Runtime versus system size for stacked settings, two panels.

Median runtime versus \(n\) for stacked settings, logarithmic vertical axis. Right, IIT 4.0 CES: bipartitions + analytical (bottom) is far below the others and reaches \(n=7\); the all-partitions + concrete baseline (labeled default in the plot legend) and + analytical coincide. Left, IIT 3.0 big Φ: + cut-one and cut-one + no-new-concepts coincide (lower pair); default and + no-new-concepts coincide (upper pair) — no-new-concepts adds nothing here.#

Median seconds, by stack (— = not measured, past the measured size range or the per-evaluation budget):

Stack

\(n=5\)

\(n=6\)

\(n=7\)

IIT 4.0 CES all-partitions + concrete

52

—

—

+ analytical relations

48

—

—

+ bipartitions

13

—

—

bipartitions + analytical

3.3

28

269

IIT 3.0 big Φ default (full cuts)

58

—

—

+ no-new-concepts

61

—

—

+ cut-one

24

225

—

cut-one + no-new-concepts

23

228

—

IIT 4.0 — cheapen distinctions first, then relations. Analytical relations alone barely helps (1.1× at \(n=5\)) because the distinctions dominate. Switching the mechanism scheme to bipartitions cuts the distinction cost ~4×. And once the distinctions are cheap, the relations become the next bottleneck, so analytical relations on top of bipartitions pays off again — another ~4× (\(13 \to 3.3\) s). The two together are ~16× at \(n=5\) and move the ceiling from \(n=5\) to \(n=7\): the full stack reaches seven units (~4.5 min) while all-partitions + concrete is already at ~52 s by five and would take tens of minutes at six. Use this combination when the 4.0 structure needs to be tractable — with the caveat that bipartitions is a formalism choice, so the seven-unit result is a different quantity than the default all-partitions one, not the same number computed faster.

IIT 3.0 — cut-one is the only setting that helps here; no-new-concepts needs a sparse system. Cut-one gives ~2.4× at \(n=5\), growing with \(n\) (the full sweep’s cut count is \(2^n\) against cut-one’s \(2n\)). No-new-concepts, though, gives nothing on this system — it skips re-evaluating mechanisms that do not specify a concept, but this strongly connected ring is dense: every one of the \(2^n-1\) mechanisms specifies a distinction, so there is nothing to skip. No-new-concepts pays off only on sparse systems with few concepts. So cut-one + no-new-concepts is indistinguishable from cut-one alone here.

Neither stack changes the exponential base — they lower the constant and the polynomial factor, buying a unit or two, not a new complexity class. The base is fixed by the formalism.

Practical guidance#

  • Provide a connectivity matrix. Missing edges let PyPhi prove reducibility without computing repertoires, pruning purviews and cuts a priori.

  • For IIT 4.0, cheapen distinctions and relations together. Pairing a cheaper mechanism partition scheme with ANALYTICAL relations compounds — above it reached seven units where all-partitions + concrete stalled at five. The partition scheme is a formalism choice, so this changes which quantity is computed.

  • Use ANALYTICAL relations when you need the relation count or summed φ but not the individual relations — it avoids the \(2^D\) enumeration entirely, and helps most once the distinctions are no longer the bottleneck.

  • Parallelize (parallel_*_evaluation) and keep repertoire caching on (the default) — the partition sweep revisits the same repertoires many times.

  • For IIT 3.0, use cut-one when an upper bound on Φ suffices; its advantage over the full sweep grows with \(n\). No-new-concepts only helps on sparse systems.

IIT 3.0 (historical)#

IIT 3.0 has three nested levels, and the exponential base grows at each. One cause–effect structure nests over mechanisms (\(2^n-1\)), cause and effect purviews (up to \(2^n-1\) each, connectivity-pruned), and the JOINT_BIPARTITION mechanism partitions (\(\approx 2^{\,m-1}\cdot 2^p\) per pair). This is \(O(n^5\,3^n)\): the base is \(3\) because each unit is in the mechanism, the purview, or neither — three choices per unit (allowing both would give \(4^n\), which pruning removes), and the \(n^5\) collects the polynomial per-operation work. One subsystem’s Φ recomputes the whole structure for each of the \(2^n\) system cuts, multiplying by \(2^n\) and taking the base to \(6\): \(O(n^5\,6^n)\). The major complex evaluates a subsystem’s Φ for every candidate subsystem; a size-\(k\) subsystem costs \(\sim 6^k\) and there are \(\binom{n}{k}\) of them, so \(\sum_k \binom{n}{k} 6^k = 7^n\) takes the base to \(7\): \(O(n^5\,7^n)\).[1]

The measured growth follows the \(3 \to 6 \to 7\) progression. After dividing out the \(n^5\) polynomial, a single cause–effect structure fits base 3.1 (\(R^2=0.999\)) and one subsystem’s Φ fits 4.7, rising toward 6 at larger sizes. The major complex (Substrate.maximal_complex, timed in benchmarks/complexity/complex_search.py) takes 0.15 / 0.31 / 4.6 / 69 s at \(n = 2/3/4/5\) — at \(n=5\) only ~1.2× the single-subsystem Φ, since the search is dominated by its largest subsystem and the ring prunes non-strongly-connected candidates, holding it below the \(7^n\) worst case.

Two approximations lower the constant: cut-one evaluates only the \(2n\) single-unit cuts rather than all \(2^n\) (an upper bound on Φ), and no-new-concepts reuses the unpartitioned distinctions across cuts (both measured under Reducing the cost, above).

Actual causation#

The actual-causation account of a transition nests like a 3.0 cause–effect structure: over the \(2^n-1\) candidate mechanisms, the \(\le 2^n-1\) candidate purviews on each side, and the mechanism partitions (JOINT_PARTITION_ALL, super-exponential per pair), with a full account recomputed for each system cut. Each evaluation compares an actual probability against a partitioned one under the configured α measure (pointwise mutual information, by default). The cost is super-exponential in \(n\), in the same family as the IIT 4.0 distinctions step; the account fits a base of 2.3 after dividing out \(n^5\) over the measured range.

References#

  • Mayner WGP, Marshall W, Albantakis L, Findlay G, Marchman R, Tononi G (2018). PyPhi: A toolbox for integrated information theory. PLOS Computational Biology 14(7): e1006343.

  • Albantakis L, Barbosa L, Findlay G, Grasso M, et al. (2023). Integrated information theory (IIT) 4.0. PLOS Computational Biology 19(10): e1011465.

  • Marshall W, Findlay G, Albantakis L, Tononi G (2026). Intrinsic units: identifying a system’s causal grain. Neuroscience of Consciousness 2026(1): niag013.

  • Zaeemzadeh A, Tononi G (2024). Upper bounds for integrated information. PLOS Computational Biology 20(8): e1012323.

  • Hanson JR, Walker SI (2023). On the non-uniqueness problem in integrated information theory. Neuroscience of Consciousness 2023(1): niad014.