# XOR Network¶

This example describes a system of three fully connected **XOR** nodes, \(n_{0}\),
\(n_{1}\) and \(n_{2}\) (no self-connections).

First let’s create the XOR network:

```
>>> import pyphi
>>> network = pyphi.examples.xor_network()
```

We’ll consider the state with all nodes **OFF**.

```
>>> state = (0, 0, 0)
```

Existence is a top-down process; the whole is more important than its parts. The first step is to confirm the existence of the whole, by finding the main complex of the network:

```
>>> main_complex = pyphi.compute.main_complex(network, state)
```

The main complex exists (\(\Phi > 0\)),

```
>>> main_complex.phi
1.874999
```

and it consists of the entire network:

```
>>> main_complex.subsystem
Subsystem((n0, n1, n2))
```

Knowing what exists at the system level, we can now investigate the existence of concepts within the complex.

```
>>> constellation = main_complex.unpartitioned_constellation
>>> len(constellation)
3
>>> [concept.mechanism for concept in constellation]
[(0, 1), (0, 2), (1, 2)]
```

There are three concepts in the constellation. They are all the possible second order mechanisms: \(n_{0}n_{1}\), \(n_{0}n_{2}\) and \(n_{1}n_{2}\).

Focusing on the concept specified by mechanism \(n_{0}n_{1}\), we investigate existence, and the irreducible cause and effect. Based on the symmetry of the network, the results will be similar for the other second order mechanisms.

```
>>> concept = constellation[0]
>>> concept.mechanism
(0, 1)
>>> concept.phi
0.5
```

The concept has \(\varphi = \frac{1}{2}\).

```
>>> concept.cause.purview
(0, 1, 2)
>>> concept.cause.repertoire
array([[[ 0.5, 0. ],
[ 0. , 0. ]],
[[ 0. , 0. ],
[ 0. , 0.5]]])
```

So we see that the cause purview of this mechanism is the whole system \(n_{0}n_{1}n_{2}\), and that the repertoire shows a \(0.5\) of probability the past state
being `(0, 0, 0)`

and the same for `(1, 1, 1)`

:

```
>>> concept.cause.repertoire[(0, 0, 0)]
0.5
>>> concept.cause.repertoire[(1, 1, 1)]
0.5
```

This tells us that knowing both \(n_{0}\) and \(n_{1}\) are currently **OFF** means that
the past state of the system was either all **OFF** or all **ON** with equal
probability.

For any reduced purview, we would still have the same information about the
elements in the purview (either all **ON** or all **OFF**), but we would lose
the information about the elements outside the purview.

```
>>> concept.effect.purview
(2,)
>>> concept.effect.repertoire
array([[[ 1., 0.]]])
```

The effect purview of this concept is the node \(n_{2}\). The mechanism \(n_{0}n_{1}\) is
able to completely specify the next state of \(n_{2}\). Since both nodes are
**OFF**, the next state of \(n_{2}\) will be **OFF**.

The mechanism \(n_{0}n_{1}\) does not provide any information about the next state of
either \(n_{0}\) or \(n_{1}\), because the relationship depends on the value of \(n_{2}\).
That is, the next state of \(n_{0}\) (or \(n_{1}\)) may be either **ON** or **OFF**,
depending on the value of \(n_{2}\). Any purview larger than \(n_{2}\) would be reducible
by pruning away the additional elements.

Main Complex: \(n_{0}n_{1}n_{2}\) with \(\Phi = 1.875\) | |||
---|---|---|---|

Mechanism |
\(\varphi\) | Cause Purview |
Effect Purview |

\(n_{0}n_{1}\) | 0.5 | \(n_{0}n_{1}n_{2}\) | \(n_{2}\) |

\(n_{0}n_{2}\) | 0.5 | \(n_{0}n_{1}n_{2}\) | \(n_{1}\) |

\(n_{1}n_{2}\) | 0.5 | \(n_{0}n_{1}n_{2}\) | \(n_{0}\) |

An analysis of the intrinsic existence of this system reveals that the main
complex of the system is the entire network of **XOR** nodes. Furthermore, the
concepts which exist within the complex are those specified by the second-order
mechanisms \(n_{0}n_{1}\), \(n_{0}n_{2}\), and \(n_{1}n_{2}\).

To understand the notion of intrinsic existence, in addition to determining what exists for the system, it is useful to consider also what does not exist.

Specifically, it may be surprising that none of the first order mechanisms
\(n_{0}\), \(n_{1}\) or \(n_{2}\) exist. This physical system of **XOR** gates is sitting on
the table in front of me; I can touch the individual elements of the system, so
how can it be that they do not exist?

That sort of existence is what we term extrinsic existence. The **XOR** gates
exist for me as an observer, external to the system. I am able to manipulate
them, and observe their causes and effects, but the question that matters for
intrinsic existence is, do they have irreducible causes and effects within
the system? There are two reasons a mechanism may have no irreducible
cause-effect power: either the cause-effect power is completely reducible, or
there was no cause-effect power to begin with. In the case of elementary
mechanisms, it must be the latter.

To see this, again due to symmetry of the system, we will focus only on the mechanism \(n_{0}\).

```
>>> subsystem = pyphi.examples.xor_subsystem()
>>> n0 = (0,)
>>> n0n1n2 = (0, 1, 2)
```

In order to exist, a mechanism must have irreducible cause and effect power within the system.

```
>>> subsystem.cause_info(n0, n0n1n2)
0.5
>>> subsystem.effect_info(n0, n0n1n2)
0.0
```

The mechanism has no effect power over the entire subsystem, so it cannot have effect power over any purview within the subsystem. Furthermore, if a mechanism has no effect power, it certainly has no irreducible effect power. The first-order mechanisms of this system do not exist intrinsically, because they have no effect power (having causal power is not enough).

To see why this is true, consider the effect of \(n_{0}\). There is no self-loop, so
\(n_{0}\) can have no effect on itself. Without knowing the current state of \(n_{0}\),
in the next state \(n_{1}\) could be either **ON** or **OFF**. If we know that the
current state of \(n_{0}\) is **ON**, then \(n_{1}\) could still be either **ON** or
**OFF**, depending on the state of \(n_{2}\). Thus, on its own, the current state of
\(n_{0}\) does not provide any information about the next state of \(n_{1}\). A similar
result holds for the effect of \(n_{0}\) on \(n_{2}\). Since \(n_{0}\) has no effect power
over any element of the system, it does not exist from the intrinsic
perspective.

To complete the discussion, we can also investigate the potential third order mechanism \(n_{0}n_{1}n_{2}\). Consider the cause information over the purview \(n_{0}n_{1}n_{2}\):

```
>>> subsystem.cause_info(n0n1n2, n0n1n2)
0.749999
```

Since the mechanism has nonzero cause information, it has causal power over the system—but is it irreducible?

```
>>> mip = subsystem.mip_past(n0n1n2, n0n1n2)
>>> mip.phi
0.0
>>> mip.partition
(Part(mechanism=(0,), purview=()), Part(mechanism=(1, 2), purview=(0, 1, 2)))
```

The mechanism has \(ci = 0.75\), but it is completely reducible (\(\varphi = 0\)) to the partition

This result can be understood as follows: knowing that \(n_{1}\) and \(n_{2}\) are
**OFF** in the current state is sufficient to know that \(n_{0}\), \(n_{1}\), and \(n_{2}\)
were all **OFF** in the past state; there is no additional information gained
by knowing that \(n_{0}\) is currently **OFF**.

Similarly for any other potential purview, the current state of \(n_{1}\) and \(n_{2}\)
being `(0, 0)`

is always enough to fully specify the previous state, so the
mechanism is reducible for all possible purviews, and hence does not exist.