Skip to content

Latest commit

 

History

History
255 lines (184 loc) · 7.94 KB

actual_causation.rst

File metadata and controls

255 lines (184 loc) · 7.94 KB

Actual Causation

This section demonstrates how to use PyPhi to evaluate actual causation, as described in

Albantakis L, Marshall W, Hoel E, Tononi G (2019). What Caused What? A quantitative Account of Actual Causation Using Dynamical Causal Networks. Entropy, 21 (5), pp. 459. https://doi.org/10.3390/e21050459

First, we'll import the modules we need:

>>> import pyphi >>> from pyphi import actual, config, Direction

never

This py.test fixture resets PyPhi config back to defaults after running this doctest. This will not be shown in the output markup.

>>> getfixture('restore_config_afterwards')

Configuration

Before we begin we need to set some configuration values. The correct way of partitioning for actual causation is using the 'ALL' partitions setting; 'TRI'-partitions are a reasonable approximation. In case of ties the smaller purview should be chosen. IIT 3.0 style bipartitions will give incorrect results.

>>> config.PARTITION_TYPE = 'TRI' >>> config.PICK_SMALLEST_PURVIEW = True

When calculating a causal account of the transition between a set of elements at time and a set of elements at time , with and being subsets of the same system, the transition should be valid according to the system's TPM. However, the state of at does not necessarily need to have a valid previous state so we can disable state validation:

>>> config.VALIDATE_SUBSYSTEM_STATES = False

Computation

We will look at how to perform computations over the basic OR-AND network introduced in Figure 1 of the paper.

>>> network = pyphi.examples.actual_causation()

This is a standard PyPhi so we can look at its TPM:

>>> pyphi.convert.state_by_node2state_by_state(network.tpm) array([[1., 0., 0., 0.], [0., 1., 0., 0.], [0., 1., 0., 0.], [0., 0., 0., 1.]])

The OR gate is element 0, and the AND gate is element 1 in the network.

>>> OR = 0 >>> AND = 1

We want to observe both elements at and , with OR ON and AND OFF in both observations:

>>> X = Y = (OR, AND) >>> X_state = Y_state = (1, 0)

The object is the core of all actual causation calculations. To instantiate a , we pass it a , the state of the network at and , and elements of interest at and . Note that PyPhi requires the state to be the state of the entire network, not just the state of the nodes in the transition.

>>> transition = actual.Transition(network, X_state, Y_state, X, Y)

Cause and effect repertoires can be obtained for the transition. For example, as shown on the right side of Figure 2B, we can compute the effect repertoire to see how constrains the probability distribution of the purview :

>>> transition.effect_repertoire((OR,), (OR, AND)) array([[0. , 0. ], [0.5, 0.5]])

Similarly, as in Figure 2C, we can compute the cause repertoire of to see how it constrains the purview :

>>> transition.cause_repertoire((OR, AND), (OR,)) array([[0.5], [0.5]])

Note

In all methods the constraining occurence is passed as the mechanism argument and the constrained occurence is the purview argument. This mirrors the terminology introduced in the IIT code.

also provides methods for computing cause and effect ratios. For example, the effect ratio of constraining (as shown in Figure 3A) is computed as follows:

>>> transition.effect_ratio((OR,), (OR,)) 0.415037

The effect ratio of constraining is negative:

>>> transition.effect_ratio((OR,), (AND,)) -0.584963

And the cause ratio of constraining (Figure 3B) is:

>>> transition.cause_ratio((OR,), (OR, AND)) 0.415037

We can evaluate for a particular pair of occurences, as in Figure 3C. For example, to find the irreducible effect ratio of , we use the find_mip method:

>>> link = transition.find_mip(Direction.EFFECT, (OR, AND), (OR, AND))

This returns a object, with a number of useful properties. This particular MIP is reducible, as we can see by checking the value of :

>>> link.alpha 0.0

The partition property shows the minimum information partition that reduces the occurence and candidate effect:

>>> link.partition # doctest: +NORMALIZE_WHITESPACE

∅ OR AND

─── ✕ ─── ✕ ───

∅ OR AND

Let's look at the MIP for the irreducible occurence constraining (Figure 3D). This candidate causal link has positive :

>>> link = transition.find_mip(Direction.CAUSE, (OR, AND), (OR, AND)) >>> link.alpha 0.169925

To find the actual cause or actual effect of a particular occurence, use the find_actual_cause or find_actual_effect methods:

>>> transition.find_actual_cause((OR, AND)) CausalLink α = 0.1699 [OR, AND] ◀━━ [OR, AND]

Accounts

The complete causal account of our transition can be computed with the account function:

>>> account = actual.account(transition) >>> print(account) # doctest: +NORMALIZE_WHITESPACE <BLANKLINE> Account (5 causal links) *********************************** Irreducible effects α = 0.415 [OR] ━━▶ [OR] α = 0.415 [AND] ━━▶ [AND] Irreducible causes α = 0.415 [OR] ◀━━ [OR] α = 0.415 [AND] ◀━━ [AND] α = 0.1699 [OR, AND] ◀━━ [OR, AND]

We see that this function produces the causal links shown in Figure 4. The object is a subclass of tuple, and can manipulated the same:

>>> len(account) 5

Irreducible Accounts

The irreducibility of the causal account of our transition of interest can be evaluated using the following function:

>>> sia = actual.sia(transition) >>> sia.alpha 0.169925

As shown in Figure 4, the second order occurence is destroyed by the MIP:

>>> sia.partitioned_account # doctest: +NORMALIZE_WHITESPACE <BLANKLINE> Account (4 causal links) ************************** Irreducible effects α = 0.415 [OR] ━━▶ [OR] α = 0.415 [AND] ━━▶ [AND] Irreducible causes α = 0.415 [OR] ◀━━ [OR] α = 0.415 [AND] ◀━━ [AND]

The partition of the MIP is available in the cut property:

>>> sia.cut # doctest: +NORMALIZE_WHITESPACE KCut CAUSE ∅ OR AND ─── ✕ ─── ✕ ─── ∅ OR AND

To find all irreducible accounts within the transition of interest, use nexus:

>>> all_accounts = actual.nexus(network, X_state, Y_state)

This computes for all permutations of of elements in and and returns a tuple of all objects with :

>>> for n in all_accounts: ... print(n.transition, n.alpha) Transition([OR] ━━▶ [OR]) 2.0 Transition([AND] ━━▶ [AND]) 2.0 Transition([OR, AND] ━━▶ [OR, AND]) 0.169925

The causal_nexus function computes the maximally irreducible account for the transition of interest:

>>> cn = actual.causal_nexus(network, X_state, Y_state) >>> cn.alpha 2.0 >>> cn.transition Transition([OR] ━━▶ [OR])

Disjunction of conjunctions

If you are interested in exploring further, the disjunction of conjunctions network from Figure 7 is provided as well:

>>> network = pyphi.examples.disjunction_conjunction_network() >>> cn = actual.causal_nexus(network, (1, 0, 1, 0), (0, 0, 0, 1))

The only irreducible transition is from to , with of 2.0:

>>> cn.transition Transition([C] ━━▶ [D]) >>> cn.alpha 2.0