Objectif : l’Integrated Information Theory (IIT), introduite par Giulio Tononi et collaborateurs, propose une mesure de la conscience à partir de la quantité d’information intégrée par un système. En pratique :
Un système (réseau de neurones, circuit logique, etc.) est représenté par une Transition Probability Matrix (TPM).
L’information intégrée est notée \(\Phi\) (Phi). PyPhi calcule \(\Phi\) pour des sous-systèmes et explore la structure causale (Cause-Effect Structure, ou CES).
L’objectif pédagogique de ce notebook est de créer un petit réseau, de définir un état, et de calculer \(\Phi\) pour différents sous-ensembles (subsystèmes).
Objectifs du TP
Comprendre la représentation d’un système dynamique discret via une TPM.
Manipuler les objets de base de PyPhi : Network, Subsystem.
Calculer et interpréter la valeur \(\Phi\) (degré d’irréductibilité).
Explorer la structure causale (CES) d’un état donné.
Résumé des concepts clés
Concept
Explication simple
Analogie
TPM
Les règles du jeu. Comment le système évolue.
Les lois de la physique.
État
La configuration actuelle (0 ou 1) des nœuds.
Une photo instantanée du cerveau.
\(\Phi\) (Big Phi)
Le niveau d’intégration du système entier.
La solidité d’un nœud marin (tient-il tout seul ?).
MIP
Le point faible du système (Minimum Information Partition).
Sélectionner l’environnement nouvellement créé comme noyau.
Cadre. Ce notebook établit le calcul opérationnel de \(\Phi\) (petite phi) sur un réseau toy avec PyPhi : construction du sous-système, mécanisme d’information minimale irréductible (MIP), puis cause-effect structure (CES). C’est le socle mécanique de toute la série IIT.
Du côté ICT. L’Epic #4588 demande : qu’est-ce qu’une « strate » mesure quand on parle d’information intégrée ? Le \(\Phi\) calculé ici en est l’instrument. Le fil ICT qui prolonge cette mécanique — la dissolution des scalaires — suit ce qui arrive à \(\Phi\), F, K quand on les pousse hors de leur substrat d’origine (ICT-1 → ICT-22).
import warnings# pyemd (importe par pyphi) emet un avertissement de deprecation pkg_resources qui fuite le chemin site-packages.warnings.filterwarnings("ignore", message=".*pkg_resources is deprecated.*", category=UserWarning)# Installation defensive : pyphi est deja present dans le kernel dedie (env conda pyphi).# On ne lance pip que s'il manque, pour eviter la sortie bruyante (chemins site-packages).import importlib.util, subprocess, sysif importlib.util.find_spec("pyphi") isNone: subprocess.run([sys.executable, "-m", "pip", "install", "-q", "pyphi"], check=True)print("pyphi installe.")else:import pyphiprint(f"pyphi deja installe ({pyphi.__version__}).")
Welcome to PyPhi!
If you use PyPhi in your research, please cite the paper:
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.
https://doi.org/10.1371/journal.pcbi.1006343
Documentation is available online (or with the built-in `help()` function):
https://pyphi.readthedocs.io
To report issues, please use the issue tracker on the GitHub repository:
https://github.com/wmayner/pyphi
For general discussion, you are welcome to join the pyphi-users group:
https://groups.google.com/forum/#!forum/pyphi-users
To suppress this message, either:
- Set `WELCOME_OFF: true` in your `pyphi_config.yml` file, or
- Set the environment variable PYPHI_WELCOME_OFF to any value in your shell:
export PYPHI_WELCOME_OFF='yes'
pyphi deja installe (1.2.0).
Une fois PyPhi installe, importons la librairie et verifions la version disponible.
import warnings# pyemd (importe par pyphi) emet un avertissement de deprecation pkg_resources qui fuite le chemin site-packages.warnings.filterwarnings("ignore", message=".*pkg_resources is deprecated.*", category=UserWarning)import pyphiprint("PyPhi version:", pyphi.__version__)
PyPhi version: 1.2.0
## 3. Création d’un réseau simple (Network)
3.1. Structure d’un réseau
Un Network dans PyPhi est défini par : - Une TPM (ExplicitTPM) en forme de matrice multidimensionnelle ou un array 2D. - Une connectivity matrix (CM), indiquant comment les nœuds sont connectés.
3.2. Exemple : un circuit logique
Nous allons créer un réseau (circuit) minimaliste à 3 nœuds (A, B, C) :
A : passerelle logique, reçoit des entrées de B et C
B : un XOR des entrées de A et C
C : identique à B ou un AND/OR, selon l’exemple souhaité
import numpy as npimport pyphi# Exemple d'un petit réseau XOR# 3 noeuds : A, B, C# On utilise un exemple déjà inclus dans pyphi.examplesnetwork = pyphi.examples.xor_network()print("Nodes:", network.node_labels)print("TPM shape:", network.tpm.shape)print("Connectivity matrix:\n", network.cm)
Comment ça marche ?
- pyphi.examples.xor_network() renvoie un réseau (Network) de taille 3, où chaque nœud est un XOR à deux entrées (sans auto-connexion).
- La TPM est stockée dans network.tpm, et chaque dimension correspond à un état binaire (0/1). La TPM est un tableau multidimensionnel de taille (2, 2, 2, 3), reflétant les états binaires pour 3 nœuds. La matrice de connectivité montre les liens (XOR signifie que chaque nœud dépend des deux autres sans boucles sur soi-même).
3.3. Inspection de la TPM
Pour mieux comprendre le fonctionnement du réseau, vous pouvez examiner directement les valeurs de la matrice de transition (TPM). Celle-ci peut être soit en state-by-state (SBS) ou state-by-node (SBN) selon votre cas. PyPhi propose des utilitaires de conversion.
import pyphi.convertsbn_tpm = network.tpmprint("TPM (state-by-node) shape:", sbn_tpm.shape)# Pour visualiser un 'slice' ou un 'flatten' :print("Premier 'slice' de la TPM (correspondant à un sous-état) :\n", sbn_tpm[0])# Passer au format state-by-state pour mieux le parcourirsbs_tpm = pyphi.convert.state_by_node2state_by_state(sbn_tpm)print("\nTPM (state-by-state) shape:", sbs_tpm.shape)print("Quelques lignes du TPM:\n", sbs_tpm[:4])
TPM (state-by-node) shape: (2, 2, 2, 3)
Premier 'slice' de la TPM (correspondant à un sous-état) :
[[[0. 0. 0.]
[1. 1. 0.]]
[[1. 0. 1.]
[0. 1. 1.]]]
TPM (state-by-state) shape: (8, 8)
Quelques lignes du TPM:
[[1. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 1. 0.]
[0. 0. 0. 0. 0. 1. 0. 0.]
[0. 0. 0. 1. 0. 0. 0. 0.]]
## 4. Définition d’un Subsystem et calcul de \(\Phi\)
4.1. Sous-système (Subsystem)
Un Subsystem se définit en spécifiant : 1. Un Network ; 2. Un état du réseau (ex. (0, 0, 0) pour A=0, B=0, C=0) ; 3. Les indices de nœuds internes qu’on considère comme faisant partie du sous-système.
Ensuite, PyPhi peut calculer la valeur de \(\Phi\) pour ce sous-système.
Le Calcul de \(\Phi\) : Définition Intuitive
\(\Phi\) mesure à quel point le système est “plus que la somme de ses parties”.
Le calcul : PyPhi essaie de couper le système en deux (une “bipartition”) de toutes les manières possibles (A vs BC, B vs AC, etc.). - La coupe qui fait perdre le moins d’information est appelée la Minimum Information Partition (MIP). - \(\Phi\) est la quantité d’information perdue au niveau de cette coupe la plus faible. - Si \(\Phi > 0\), le système est irréductible (conscient selon l’IIT).
# État de départstate = (0, 0, 0)# Créons un Subsystem pour l’ensemble des nœuds (0, 1, 2)subsystem = pyphi.Subsystem(network, state, (0, 1, 2))# Calcul de Phiphi_value = pyphi.compute.phi(subsystem)print("Φ pour le sous-système (0,1,2) à l’état (0,0,0) :", phi_value)
Φ pour le sous-système (0,1,2) à l’état (0,0,0) : 1.874999
4.2. States inaccessibles et validation (StateUnreachableError)
C’est une erreur fréquente rencontrée dans PyPhi.
Le problème : Certains états du réseau peuvent être impossibles à atteindre selon la dynamique du système (la TPM). Si on force le système dans cet état “impossible”, l’IIT considère que le passé est indéfini.
Solutions possibles : 1. Choisir un état qui est atteignable (un état stable ou faisant partie d’un cycle). 2. Ou désactiver la validation (pour l’exercice) : pyphi.config.VALIDATE_SUBSYSTEM_STATES = False.
PyPhi, par défaut, peut émettre des erreurs (StateUnreachableError) si l’état que vous définissez n’est pas accessible depuis la TPM. Ci-dessous, on montre comment désactiver temporairement la validation pour s’assurer que PyPhi ne bloque pas le calcul.
# Configurer PyPhi pour ignorer les inaccessibilités d’étatspyphi.config.VALIDATE_SUBSYSTEM_STATES =False# Réessayer un état arbitrairetest_state = (1,0,0)subsys_test = pyphi.Subsystem(network, test_state, (0,1,2))try: val_test = pyphi.compute.phi(subsys_test)print(f"État {test_state} -> Φ = {val_test:.5f}")except pyphi.exceptions.StateUnreachableError:print("État inaccessible, PyPhi a lancé une exception !")
État inaccessible, PyPhi a lancé une exception !
On peut également calculer \(\Phi\) pour d’autres états accessibles:
# Exemple d'états stables pour éviter StateUnreachableErrorfor s in [(0,0,0), (0,1,1), (1,1,0)]: subsys = pyphi.Subsystem(network, s, (0,1,2)) val = pyphi.compute.phi(subsys)print(f"État {s} -> Φ = {val:.5f}")
État (0, 0, 0) -> Φ = 1.87500
État (0, 1, 1) -> Φ = 1.87500
État (1, 1, 0) -> Φ = 1.87500
Interprétation : pourquoi ces trois états donnent-ils le même \(\Phi\) ?
Vous venez de calculer \(\Phi\) pour trois états distincts — (0,0,0), (0,1,1) et (1,1,0) — et les trois donnent exactement la même valeur \(\Phi = 1.87500\). Ce n’est ni une coïncidence numérique ni un bug de PyPhi : c’est une propriété profonde de la mesure.
\(\Phi\) ne dépend pas de l’état pris isolément, mais de la structure cause-effet (CES) du sous-système dans cet état. Sur le réseau XOR canonique (déterministe), les trois états testés appartiennent à un même cycle de la dynamique, et ils engendrent des structures cause-effet identiques — mêmes mécanismes, mêmes purviews, mêmes petits \(\varphi\) par distinction. Comme \(\Phi\) est le minimum informationnel sur l’ensemble de cette structure (la coupe la plus faible du graphe cause-effet), et que la structure coïncide d’un état à l’autre, \(\Phi\) coïncide aussi.
La leçon conceptuelle est essentielle : \(\Phi\) quantifie une propriété intrinsèque au sous-système et à sa connectivité, évaluée relativement à un état mais non réductible à lui seul. Deux états différents peuvent porter la même « expérience » informationnelle dès lors que leur structure cause-effet coïncide. C’est précisément ce qui distingue \(\Phi\) d’une simple entropie de l’état ou d’un compte de corrélations : il capte l’organisation causale, pas la configuration instantanée.
À retenir : sur un réseau bruité ou asymétrique, la structure cause-effet varierait d’un état à l’autre et \(\Phi\) en différerait. L’invariance observée ici est la signature d’un réseau déterministe symétrique — elle disparaîtrait dès qu’on introduit du hasard ou une asymétrie dans la matrice de transition (TPM). Ce point sera réexploré au paragraphe suivant sur les sous-systèmes partiels.
Démonstration : une asymétrie de la TPM brise l’invariance de \(\Phi\)
L’interprétation précédente énonçait un fait fort : sur le réseau XOR symétrique, \(\Phi = 1{,}875\) est invariant sur les états atteignables, et cette invariance est la signature d’une dynamique déterministe symétrique. Mais elle ajoutait une prédiction — « l’invariance disparaîtrait dès qu’on introduit une asymétrie dans la TPM » — qui, jusqu’ici, restait non démontrée.
Vérifions-le empiriquement. Nous construisons un réseau quasi identique au XOR canonique, sauf sur un seul noeud : nous conservons node0 = XOR(b, c) et node1 = XOR(a, c), mais nous remplaçons node2 = XOR(a, b) par la fonction booléenne asymétrique node2 = OR(a, AND(b, c)). La connectivité reste complète. Cette unique perturbation suffit-elle à faire varier \(\Phi\) d’un état à l’autre ? PyPhi va trancher.
# Démonstration : une asymétrie de la TPM brise l'invariance de Phi# Le réseau XOR canonique (cellule précédente) est parfaitement symétrique :# chaque noeud calcule le XOR des deux autres, donc la structure cause-effet# coïncide sur les 4 états atteignables -> Phi = 1.875 invariant (cellule 14).# Perturbons MINIMALEMENT la dynamique : gardons node0 = XOR(b,c) et# node1 = XOR(a,c), mais modifions node2 en OR(a, AND(b,c)) -- une fonction# booléenne asymétrique. Cette unique asymétrie suffit à faire varier Phi.# Matrice de transition (TPM) du réseau asymétrique -- format état-par-noeud.tpm_asym = np.zeros((2, 2, 2, 3))for a in (0, 1):for b in (0, 1):for c in (0, 1): n0 = (b + c) %2# node0 = XOR(b, c) (canonique) n1 = (a + c) %2# node1 = XOR(a, c) (canonique) n2 =int(a or (b and c)) # node2 = OR(a, AND(b, c)) (PERTURBÉ) tpm_asym[a, b, c] = [n0, n1, n2]# Connectivité complète (chaque noeud lit les deux autres), comme le canonique.cm = np.ones((3, 3), dtype=int)network_asym = pyphi.Network(tpm_asym, cm)# Rappel -- réseau SYMÉTRIQUE canonique : Phi invariantphi_sym = pyphi.compute.phi(pyphi.Subsystem(network, (0, 0, 0), (0, 1, 2)))print("="*62)print("RÉSEAU SYMÉTRIQUE canonique (XOR) : Phi invariant")print("="*62)print(f" État (0,0,0) -> Phi = {phi_sym:.4f} (idem sur (0,1,1), (1,0,1), (1,1,0))")print("\n"+"="*62)print("RÉSEAU ASYMÉTRIQUE (node2 perturbé) : Phi varie selon l'état")print("="*62)phis_asym = []for s in [(a, b, c) for a in (0, 1) for b in (0, 1) for c in (0, 1)]:try: val = pyphi.compute.phi(pyphi.Subsystem(network_asym, s, (0, 1, 2))) phis_asym.append((s, val))print(f" État {s} -> Phi = {val:.4f}")except pyphi.exceptions.StateUnreachableError:print(f" État {s} -> inaccessible (hors dynamique)")vals =sorted({round(v, 4) for _, v in phis_asym})print("-"*62)print(f" Valeurs distinctes de Phi : {len(vals)} -> {vals}")print(f" CONSTAT : l'asymétrie d'un seul noeud suffit à briser l'invariance.")print(f" Phi passe de 1.875 (unique, symétrique) à [{min(vals):.4f} .. {max(vals):.4f}]")print(f" ({len(vals)} valeurs distinctes sur {len(phis_asym)} états atteignables).")
État (1, 1, 1) -> Phi = 1.8669
--------------------------------------------------------------
Valeurs distinctes de Phi : 7 -> [0.8073, 1.0781, 1.3021, 1.5781, 1.8669, 2.0569, 2.7431]
CONSTAT : l'asymétrie d'un seul noeud suffit à briser l'invariance.
Phi passe de 1.875 (unique, symétrique) à [0.8073 .. 2.7431]
(7 valeurs distinctes sur 7 états atteignables).
Interprétation : la symétrie, condition de l’invariance de \(\Phi\)
Le verdict de PyPhi est net et confirme la prédiction :
Réseau
États atteignables
\(\Phi\)
Invariance
XOR symétrique canonique
4 (000, 011, 101, 110)
\(1{,}875\) partout
Oui (1 valeur)
XOR asymétrique (node2 perturbé)
7
de \(0{,}81\) à \(2{,}74\)
Non (7 valeurs distinctes)
Pourquoi l’invariance cède-t-elle ? Sur le réseau symétrique, les quatre états atteignables sont reliés par les permutations de noeuds : la structure cause-effet (CES) qu’ils engendrent est identique, donc le \(\Phi\) (information intégrée minimale sur cette structure) coïncide. Dès qu’on asymétrise un seul noeud, cette équivalence par permutation disparaît : chaque état engendre désormais une CES spécifique, et \(\Phi\) devient dépendant de l’état.
La leçon : \(\Phi\) n’est pas une constante du réseau, c’est une quantité évaluée relativement à un état. Le cas symétrique est un cas particulier remarquable où plusieurs états partagent la même CES — d’où l’invariance observée. Ce partage est fragile : il suffit d’une asymétrie locale pour le détruire et révéler la sensibilité de \(\Phi\) à la configuration exacte du sous-système. C’est précisément cette sensibilité qui fait de \(\Phi\) une mesure riche de l’organisation causale d’un mécanisme dans un état donné, et non un simple invariant topologique.
À retenir : l’invariance de \(\Phi\) sur le XOR canonique n’est pas une propriété générale de la mesure — c’est un effet de la symétrie parfaite du réseau. La briser, même partiellement, suffit à restaurer la dépendance de \(\Phi\) vis-à-vis de l’état.
Le complexe majeur : la recherche de frontière intégrée
Jusqu’ici, nous avons choisi la frontière : chaque Subsystem(network, state, nodes) fixe des bords à la main. PyPhi embarque aussi la recherche de la frontière qui maximise \(\Phi\) — le complexe majeur, mise en œuvre du postulat d’exclusion d’IIT 3.0 (parmi les candidats, seul le maximiseur compte) :
pyphi.compute.major_complex(network, state) # le sous-système de big-Phi maximalpyphi.compute.complexes(network, state) # tous les sous-systèmes de big-Phi > 0
Le problème « qui décide des bords ? » reçoit ici sa réponse moteur : la bibliothèque énumère les candidats et tranche. IIT-4 consacre un notebook entier à ce choix de frontière — y compris le cas où le complexe majeur n’est pas le réseau entier.
# --- Le moteur tranche lui-meme : recherche du complexe majeur sur le reseau XOR ---pyphi.config.PROGRESS_BARS =False# sorties propres (les cellules precedentes laissent les barres)complexe_majeur = pyphi.compute.major_complex(network, state)noeuds_cm =tuple(network.node_labels[i] for i in complexe_majeur.subsystem.node_indices)print("major_complex(network, (0,0,0)) :")print(" noeuds retenus :", noeuds_cm, "| big-Phi = %.5f"% complexe_majeur.phi)print()print("complexes(network, (0,0,0)) — tous les sous-systemes de big-Phi > 0 :")for sia in pyphi.compute.complexes(network, state): noms_c =tuple(network.node_labels[i] for i in sia.subsystem.node_indices)print(" %-10s big-Phi = %.5f"% (str(noms_c), sia.phi))print()print("Sur ce reseau XOR, le complexe majeur est le systeme ENTIER (maximiseur unique) ;")print("les trois paires sont ex aequo a Phi = 1.0 — sous le maximum, pas au sommet.")
major_complex(network, (0,0,0)) :
noeuds retenus : ('A', 'B', 'C') | big-Phi = 1.87500
complexes(network, (0,0,0)) — tous les sous-systemes de big-Phi > 0 :
('A', 'B', 'C') big-Phi = 1.87500
('B', 'C') big-Phi = 1.00000
('A', 'C') big-Phi = 1.00000
('A', 'B') big-Phi = 1.00000
Sur ce reseau XOR, le complexe majeur est le systeme ENTIER (maximiseur unique) ;
les trois paires sont ex aequo a Phi = 1.0 — sous le maximum, pas au sommet.
Exercice 1 : Phi d’un sous-système partiel
Le calcul de Phi ci-dessus utilise les 3 noeuds (0,1,2). Que se passe-t-il si on ne considère qu’un sous-ensemble de noeuds, par exemple (0,1) uniquement ?
Objectif : Créez un sous-système avec uniquement les noeuds (0,1) à l’état (0,0,0) et comparez sa valeur Phi avec celle du système complet.
Questions : - Phi est-il plus grand ou plus petit avec 2 noeuds qu’avec 3 ? - Combien de concepts la CES d’un sous-système partiel contient-elle ?
Indice : pyphi.Subsystem(network, state, (0, 1)) crée le sous-système partiel. Puis pyphi.compute.phi(...) pour le Phi et pyphi.compute.ces(...) pour la CES.
# Exercice 1 : Phi d'un sous-systeme partiel (noeuds 0 et 1 uniquement)# TODO etudiant : creer un sous-systeme avec (0, 1) a l'etat (0,0,0)# et calculer phi + nombre de concepts dans la CES# Indice : pyphi.Subsystem(network, (0,0,0), (0, 1))# Indice : pyphi.compute.phi(subsystem_2noeuds) pour Phi# Indice : len(pyphi.compute.ces(subsystem_2noeuds)) pour le nombre de conceptsresult =None# TODO etudiant : remplacer par le calcul Phi partiel vs completif result isnotNone:print(f"Resultat: {result}")else:print("Exercice a completer")
Exercice a completer
## 5. Concepts, mécanismes, et structure cause-effet (CES)
PyPhi peut également détailler la structure de cause-effet (CES) :
Chaque concept correspond à un mécanisme (ex. nœud simple ou sous-groupe de nœuds) et à son purview (cause et/ou effet).
ces = pyphi.compute.ces(subsystem)print("Nombre de concepts dans la CES :", len(ces))print("Liste des mécanismes :", ces.labeled_mechanisms)
Nombre de concepts dans la CES : 3
Liste des mécanismes : (['A', 'B'], ['A', 'C'], ['B', 'C'])
5.1. Analyse d’un concept spécifique
Chaque concept est défini par un mécanisme (un ensemble de nœuds) et un purview (un ensemble de nœuds qui subissent ses effets ou le causent). Explorons le premier concept dans la CES, pour comprendre sa cause / effet et son petit phi (\(\\varphi\)).
# Prenons le premier concept dans la CESfirst_concept = ces[0]print("Mécanisme:", first_concept.mechanism)print("Cause purview:", first_concept.cause.purview)print("Cause repertoire:\n", first_concept.cause.repertoire)print("Effect purview:", first_concept.effect.purview)print("Effect repertoire:\n", first_concept.effect.repertoire)print("Petit phi (φ) =", first_concept.phi)
Le premier concept analysé (mécanisme {A,B}) a un petit phi de 0.5 et un effect purview sur C uniquement. Les autres concepts de la CES peuvent avoir des structures très différentes.
Objectif : Sélectionnez le concept correspondant au mécanisme {A,C} (le deuxième concept de la CES) et analysez son cause/effect purview et son petit phi.
Indice : Utilisez ces[1] pour accéder au deuxième concept. Comparez les purviews avec le premier concept. Les purviews sont-ils les mêmes ? Pourquoi ?
# Exercice 2 : Analyser le deuxieme concept de la CES (mecanisme {A,C})# TODO etudiant : acceder a ces[1] et afficher :# - le mecanisme# - le cause purview et repertoire# - l'effect purview et repertoire# - le petit phi# Indice : le pattern est le meme que pour first_concept = ces[0] ci-dessusresult =None# TODO etudiant : remplacer par l'analyse du deuxieme conceptif result isnotNone:print(f"Resultat: {result}")else:print("Exercice a completer")
Exercice a completer
Interpretation : structure causale du premier concept
Le mécanisme {A, B} (noeuds 0 et 1) produit un concept avec :
Aspect
Valeur
Signification
Cause purview
(A, B, C)
Les 3 noeuds contribuent a causer l’etat actuel de {A, B}
Effect purview
(C,)
Le mécanisme {A, B} n’a d’effet irreductible que sur le noeud C
Petit phi
0.5
L’information integree par ce mécanisme spécifique
Le repertoire de cause montre que l’etat passe le plus probable etait (0,0,0) ou (1,1,1) avec probabilite 0.5 chacun. Le repertoire d’effet indique que C passera a l’etat 0 avec certitude (probabilite 1.0), ce qui est coherent avec le XOR : si A=0 et B=0, alors C = A XOR B = 0.
## 6. Exemple avancé : analyse de causalité et macro-subsystems
6.1 Actual Causation
PyPhi offre pyphi.actual pour analyser la causalité effective (“What caused what?”). On définit un Transition : état avant, état après, et on cherche les liens causaux irréductibles.
Cette extension de la théorie permet de comprendre non plus “combien de conscience” (système) mais “qui a causé quoi” (causalité événementielle). C’est utile pour analyser des séquences temporelles spécifiques.
import pyphiimport pyphi.actualpyphi.config.VALIDATE_SUBSYSTEM_STATES =Falsebefore_state = (1,1,1)after_state = (0,0,0)transition = pyphi.actual.Transition( network, before_state, after_state, cause_indices=(0,1,2), effect_indices=(0,1,2))account = pyphi.actual.account(transition)print("Nombre de causal links :", len(account))for link in account:print(link)
Interpretation : liens causaux de la transition (1,1,1) vers (0,0,0)
L’analyse revele 10 liens causaux irreductibles, tous avec une force alpha = 1.0. Cette saturation uniforme n’est PAS le signe d’une “structure riche” : elle reflete au contraire une limite du reseau XOR pour la causalite evenementielle. Le reseau XOR est deterministe (chaque noeud = XOR exact de ses deux voisins), donc toute transition valide est parfaitement determinee — chaque mecanisme cause son purview avec la force maximale alpha = 1.0, sans aucune nuance.
En d’autres termes : sur un reseau deterministe, la causalite evenementielle ne discrimine pas — elle attribue la meme force maximale a tous les liens. Pour voir pyphi.actual exercer sa capacite distinctive (distinguer les causes fortes des causes faibles), il faut un reseau probabiliste, dont les transitions ne sont pas parfaitement determinees. C’est l’objet de la cellule suivante.
6.1bis Causalite evenementielle sur un reseau probabiliste (discrimination)
Pour voir la causalite evenementielle discriminer entre liens forts et faibles, nous construisons un reseau noisy-AND : meme connectivite que le XOR (anneau complet a 3 noeuds A, B, C), mais chaque porte AND est bruitee — la transition n’est plus deterministe. La probabilite qu’un noeud s’allume vaut p si ses deux entrees sont allumees, sinon une petite probabilite de bruit. Avec p = 0.9, certains mecanismes causent leur purview de maniere forte (alpha eleve) et d’autres de maniere faible (alpha faible) : la machinerie pyphi.actual peut alors distinguer les vraies causes des causes marginales, ce qu’elle ne pouvait pas faire sur le reseau XOR sature.
import numpy as npimport pyphi.actualpyphi.config.VALIDATE_SUBSYSTEM_STATES =False# Reseau noisy-AND : porte AND bruitee (p=0.9 si les 2 entrees sont ON, sinon bruit).# Meme connectivite que le XOR (anneau complet), mais TPM NON deterministe.def noisy_and_tpm(p=0.9): tpm = np.zeros((2, 2, 2, 3))for a in (0, 1):for b in (0, 1):for c in (0, 1):for ni, inp inenumerate([(b, c), (a, c), (a, b)]): tpm[a, b, c, ni] = p if (inp[0] ==1and inp[1] ==1) else (1- p) *0.5return tpmp =0.9tpm_noisy = noisy_and_tpm(p)cm_noisy = np.array([[0, 1, 1], [1, 0, 1], [1, 1, 0]])reseau_noisy = pyphi.Network(tpm_noisy, cm=cm_noisy, node_labels=("A", "B", "C"))# Une transition ou les contributions causales different d'un noeud a l'autre.avant = (1, 1, 0)apres = (0, 1, 1)transition_noisy = pyphi.actual.Transition( reseau_noisy, avant, apres, cause_indices=(0, 1, 2), effect_indices=(0, 1, 2))compte_noisy = pyphi.actual.account(transition_noisy)print(f"Transition {avant} -> {apres} sur le reseau noisy-AND (p={p})")print(f"Nombre de liens causaux : {len(compte_noisy)}")alphas = [round(float(lien.alpha), 3) for lien in compte_noisy]for lien in compte_noisy:print(lien)print()print(f"Force alpha : min={min(alphas)}, max={max(alphas)}, valeurs distinctes={sorted(set(alphas))}")
Interpretation : la causalite evenementielle discrimine
Contrairement au reseau XOR (ou alpha = 1.0 pour tous les liens), le reseau probabiliste produit des forces alpha variees — ici de l’ordre de 0.13 a 0.92. La causalite evenementielle exerce enfin sa capacite distinctive :
Liens forts (alpha eleve, ~0.92) : mecanismes qui determinent leur purview de maniere fiable dans cette transition — les “vraies” causes evenementielles.
Liens faibles (alpha bas, ~0.13) : mecanismes dont la contribution causale est marginale, noyee dans le bruit du reseau.
Cette discrimination est la raison d’etre de pyphi.actual : quantifier qui a cause quoi avec une nuance graduee, ce qu’un reseau deterministe (XOR) masque en saturant toutes les forces a la valeur maximale. C’est l’analogue, en causalite evenementielle, du constat deja fait en section 4 sur les etats inaccessibles : la richesse du calcul emergent depend de la structure probabiliste du reseau, pas seulement de sa connectivite.
Le module pyphi.macro permet d’agréger des nœuds (coarse-grain) ou de blackboxer certains éléments. On peut ainsi recalculer \(\Phi\) à une échelle différente, ce qui rejoint l’idée de l’ICT qu’on peut analyser l’information intégrée à divers niveaux.
Exercice : Exploration de la structure cause-effet
Objectifs : 1. Analyser l’impact de la topologie du réseau sur la valeur de Φ 2. Explorer la relation entre mécanismes et purviews 3. Comparer différents réseaux pour comprendre l’intégration
Contexte : Vous avez vu comment calculer Φ pour un réseau XOR simple. L’IIT suggère que la valeur de Φ dépend de la façon dont l’information est intégrée dans le système. Dans cet exercice, vous allez explorer cette relation.
Questions :
Question : Créez un réseau AND (où chaque nœud fait un AND de ses entrées) et comparez sa valeur Φ avec celle du réseau XOR. Quelle topologie produit plus d’intégration ?
Question : Pour le réseau XOR, analysez comment Φ change selon l’état du système. Existe-t-il des états où Φ = 0 ?
Question : Explorez la CES d’un sous-système à 2 nœuds vs le système complet. Comment le nombre de concepts évolue-t-il ?
# Exercice - Exploration de la structure cause-effet# 1. Créer un réseau AND et comparer Φ avec XOR# 2. Analyser Φ selon l'état# 3. Comparer CES 2-noeuds vs 3-noeuds# Exemple de structure pour le réseau AND# and_tpm = ... # Définir la TPM pour un réseau AND# and_network = pyphi.Network(and_tpm, connectivity_matrix=cm)# and_subsystem = pyphi.Subsystem(and_network, (0,0,0), (0,1,2))# print("Φ (AND):", pyphi.compute.phi(and_subsystem))print("Exercice a completer") # todo etudiant: implementer
Exercice a completer
Conclusion
Ce notebook a introduit l’Integrated Information Theory (IIT) et son implementation de reference, PyPhi, en suivant le fil qui mene des données brutes d’un système a une mesure de son integration causale.
Le pipeline PyPhi en un coup d’oeil
Étape
Objet PyPhi
Rôle
Dynamique
Network (+ TPM)
Decrit comment l’etat du système evolue, mécanisme par mécanisme
Decoupage
Subsystem
Fixe un etat de fond et isole les éléments analyses
Integration
\(\Phi\)
Mesure l’irreductibilite du tout a ses parties (la partition qui « coute » le moins)
Structure
CES (concepts)
Decompose ce que le système distingue : repertoires cause-effet de chaque mécanisme
Recherche
complexes / major_complex
Applique l’exclusion : trouve le sous-système qui maximise \(\Phi\) — la frontière n’est plus choisie à la main
Le point conceptuel central est que \(\Phi\) ne mesure pas une quantite d’information transmise, mais une information integree : ce qui serait perdu si l’on coupait le système en morceaux. Un système dont les parties sont independantes a un \(\Phi\) nul, même s’il calcule des choses complexes – l’integration, pas la performance, est le critere.
Ce que les exemples ont mis en evidence
La TPM (matrice de transition) est le point d’entree obligatoire : toute la causalite en decoule, d’ou l’importance de la validation StateUnreachableError qui protege contre l’analyse d’etats que la dynamique ne peut jamais produire.
La CES revele la qualite de l’expérience d’un système (quels concepts il porte), la ou \(\Phi\) n’en donne que la quantite.
La causalite actuelle (actual causation) repond a une question différente : non pas « quelle est la structure du système » mais « qu’est-ce qui a effectivement cause cette transition ».
Le coarse-graining / blackboxing (macro-subsystems) montre qu’un même substrat peut etre plus integre a une echelle macro qu’a l’echelle micro – l’echelle a laquelle \(\Phi\) est maximal est theoriquement privilegiee.
Limites et suite
Le calcul de \(\Phi\) est combinatoirement explosif (toutes les partitions, tous les mécanismes), ce qui confine PyPhi a de petits systèmes (quelques noeuds) – une contrainte pratique a garder en tete avant toute ambition d’echelle. Les raffinements de la théorie (IIT 4.0, calcul du \(\varphi\) au niveau des distinctions et relations) et les stratégies de passage a l’echelle sont approfondis dans le notebook IIT-2 : Sujets avances.
A retenir : l’IIT propose de mesurer la conscience comme l’integration causale irreductible d’un système sur lui-même. PyPhi rend cette definition operationnelle : on declare une dynamique (TPM), on choisit un decoupage (Subsystem), et le moteur calcule a la fois combien (\(\Phi\)) et quoi (CES) le système integre.
Où va la suite.IIT-2 approfondit le partitionnement (MIP/SIA), les répertoires cause-effet et la comparaison Big \(\Phi\) / Small \(\Phi\) ; IIT-3 traite le coarse-graining et l’échelle du \(\Phi\). Pour relier cette mécanique à la question ICT plus large de la représentation interne et des dissociations : synthese-invariants-dissociations-obstructions.md.