Grain : Issue #15477 - mode belief-state de la F-Lens. Parent : Epic #15475 (toolkit multi-instrument ICT). Dependances : #15476 (ICT-trace-contract) MERGED - split/fit IDs disponibles via ict_trace.
Question scientifique
Un etat predictif suffisant du processus generateur est-il lineairement accessible dans le residual stream, et ou et quand cette accessibilite apparait-elle ?
Ce notebook repond a “quel etat predictif est accessible ?” (mode belief-state), distinct du mode factored-geometry (#15478, ICT-36) qui etudie l’organisation geometrique des facteurs.
Protocole
Processus synthetiques a belief state ground-truth exact : Mess3 (HMM 3 etats), RRXOR (geometrie non-reductible au next-token).
Activations simulees : representation dense deterministe (couches pre/post LayerNorm capturees en deux blocs distincts).
Probe lineaire supervisee : Ridge par equation normale regularisee, split train/validation/test gele par ID.
3 exemples guides (orthogonal, Mess3, RRXOR), chacun suivi d’un exercice non resolu - chacun avec verdict falsifiable.
Hypotheses falsifiables
H1 : le residual stream predit mieux le belief state que le controle shuffle (gap >= 0.3 accuracy held-out, ou >= 0.2 sur RRXOR binaire).
H2 : sur le regime orthogonal, l’accuracy pre-LayerNorm est superieure a post-LayerNorm (LayerNorm ecrase la magnitude, mais conserve la direction).
H3 : sur RRXOR, le probe belief performe mieux que le probe next-token par >= 0.1 accuracy (dissociation belief vs next-token).
Acceptance vs #15477
Statut épistémique — Sans verdict à ce jour : aucune ligne de la matrice de dissociations ne concerne ce notebook ; son statut épistémique sera porté par la matrice le cas échéant.
Voisins et positionnement
Même geste que le S-Lens (ICT-38) : nommer les voisins de l’instrument, et ce qui nous en sépare.
Publications fondatrices (Epic #15475, bibliothèque canonique — aucun PDF committé) : Shai et al., Transformers Represent Belief State Geometry in their Residual Stream (arXiv:2405.15943) et Transformers Learn Factored Representations (arXiv:2602.02385) — c’est ce second papier, section belief-state, que le mode de cette F-Lens instrumente.
Dépôts de référence — un mot par voisin :
Astera-org/simplexity : JAX/Equinox, generative_processes/ porte déjà hidden_markov_model et mixed_state_presentation. Nos make_mess3_transitions / make_rrxor les reconstruisent à la main en numpy ; ce que cette F-Lens ajoute est le probe held-out à baselines explicites (shuffle, next-token, majoritaire), que ces dépôts ne publient pas.
Astera-org/strange-loop : voisin le plus précoce, expérience centrale en stub — rien n’en est importé.
Les recoupements de modules ci-dessus sont releves au scoping de #16224 (lecture seule des depots, aucun code copie) : ils sont reportes ici comme positionnement, pas re-mesures.
Pourquoi numpy plutôt que simplexity. La règle d’architecture de la série confine ict/ au numpy-only (torch aux scripts d’extraction) ; simplexity est Hydra + JAX/Equinox. Le portage rendrait les primitives intestables sans GPU. Aucune licence détectée sur ces dépôts (preflight Epic #15475) : aucun code n’en est copié.
Renvoi interne. La notion d’état prédictif que ces hypothèses sondent est celle de la mécanique computationnelle de Crutchfield, enseignée dans la série en ICT-17 — EpsilonMachine — à lire avant ce notebook pour qui veut la construction de l’objet, celui-ci n’en testant que l’accessibilité linéaire.
# Parametres du notebooknb_name ="ICT-37-FLens-BeliefState-Python"N_SEEDS =5# multi-seed : au moins 4 seeds (acceptance #15477)N_TRAIN =6000# points d'entrainementN_TEST =1500# points held-outDIM =32# dimension du residual stream simuleN_HIDDEN =3# nombre d'etats caches (Mess3)RNG_SEEDS = [11, 23, 47, 89, 123] # 5 seeds pour ICprint(f"=== {nb_name} ===")print(f"N_SEEDS={N_SEEDS}, N_TRAIN={N_TRAIN}, N_TEST={N_TEST}, DIM={DIM}")print(f"Verdict par hypothese : H1 SUPPORTED si accuracy_belief - accuracy_shuffle >= 0.3")print(f" H2 SUPPORTED si accuracy_preLN > accuracy_postLN (orthogonal)")print(f" H3 SUPPORTED si belief > next_token par >= 0.1 (RRXOR)")
=== ICT-37-FLens-BeliefState-Python ===
N_SEEDS=5, N_TRAIN=6000, N_TEST=1500, DIM=32
Verdict par hypothese : H1 SUPPORTED si accuracy_belief - accuracy_shuffle >= 0.3
H2 SUPPORTED si accuracy_preLN > accuracy_postLN (orthogonal)
H3 SUPPORTED si belief > next_token par >= 0.1 (RRXOR)
# Imports : numpy uniquement (acceptance #15477 primitives numpy-only)# numpy.linalg suffit : pas de scikit-learn, pas de scipy, pas de torch.# Rationale : autonomie CPU-only, reproductibilite, deploiement sur toute machine.import numpy as npprint(f"numpy version: {np.__version__}")
numpy version: 2.4.6
Primitives numpy-only
Trois briques de base, toutes numpy-only :
Primitive
Role
solve_ols_ridge
Probe lineaire Ridge par equation normale regularisee - retourne poids et intercept
Calibration pour probabilites predites vs belief ground-truth one-hot
Ces primitives sont autonomes : aucune dependance a scikit-learn, scipy, ou torch. Le probe Ridge est resolu par l’equation normale regularisee : W_hat = (X^T X + lambda I)^-1 X^T y avec lambda = 1.0 par defaut. Cela suffit largement pour un espace de dimension 32.
def solve_ols_ridge(X, y, lam=1.0):"""Probe lineaire Ridge par equation normale regularisee. X : ndarray shape (N, D) activations y : ndarray shape (N,) belief indices ou (N, K) probabilites lam : float regularisation L2 Returns W, b. """ X_ = np.column_stack([X, np.ones(X.shape[0])]) # ajout colonne biais D_plus = X_.shape[1] reg = lam * np.eye(D_plus) reg[-1, -1] =0.0# pas de regularisation sur le biaisif y.ndim ==1: W_full = np.linalg.solve(X_.T @ X_ + reg, X_.T @ y.astype(float))return W_full[:-1], W_full[-1]else: W_full = np.linalg.solve(X_.T @ X_ + reg, X_.T @ y.astype(float))return W_full[:-1, :], W_full[-1, :]def eval_heldout(y_true, y_pred, y_prob=None):"""Metriques held-out : RMSE, accuracy, R2, Brier.""" rmse =float(np.sqrt(np.mean((y_true.astype(float) - y_pred.astype(float)) **2))) acc =float(np.mean(y_true == y_pred))if y_prob isnotNone: K = y_prob.shape[1] onehot = np.eye(K)[y_true] ss_res =float(np.sum((onehot - y_prob) **2)) ss_tot =float(np.sum((onehot - onehot.mean(axis=0)) **2)) r2 =1.0- ss_res /max(ss_tot, 1e-9) brier =float(np.mean(np.sum((onehot - y_prob) **2, axis=1)))else: r2 =float("nan") brier =float("nan")return {"rmse": rmse, "accuracy": acc, "r2": r2, "brier": brier}def brier_score(y_true, y_prob):"""Brier score = MSE entre one-hot(y_true) et y_prob.""" K = y_prob.shape[1] onehot = np.eye(K)[y_true]returnfloat(np.mean(np.sum((onehot - y_prob) **2, axis=1)))# Smoke test des primitivesnp.random.seed(0)X_test = np.random.randn(100, 4)y_test = np.random.randint(0, 3, 100)W, b = solve_ols_ridge(X_test, y_test)y_pred_test = np.clip(np.round(X_test @ W + b).astype(int), 0, 2)print(f"Smoke test primitives OK : W.shape={W.shape}, accuracy_test={np.mean(y_test == y_pred_test):.3f}")
Smoke test primitives OK : W.shape=(4,), accuracy_test=0.340
Generateurs de processus synthetiques (conformes #16225)
Deux processus a belief ground-truth exact, importes du module ict – plus aucune redefinition inline :
Processus de Marzen & Crutchfield (2017), Nearly maximally predictive features and their dimensions (reference [20] de arXiv:2405.15943). Trois etats caches, persistance p_stay = 0.95, alphabet ternaire discret {0, 1, 2} dont l’emission ne revele pas l’etat (emission_diag = 0.5). Le belief ground-truth est la distribution filtree P(s_t | obs_0..t) – un point du 2-simplexe, pas l’etat cache.
Le processus repete les triplets (r1, r2, r1 XOR r2) : correlations par paires nulles, spectre plat, mais contrainte de triplet deterministe. Epsilon-machine a 5 etats causaux (machine Mealy : emissions sur les aretes). Sa mixed-state presentation compte 36 croyances distinctes (31 transitoires + 5 recurrentes, litterature p. 17 Fig. 7) – et plusieurs de ces croyances partagent la meme prediction next-token : c’est la dissociation que l’exercice 3 mesure.
Les deux generateurs viennent de ict/bench_factorise.py (numpy-only) et la primitive MSP de ict/mixed_state.py (BFS sequence -> croyance).
# Racine canonique de la serie : remonte les parents depuis le dossier du# notebook jusqu'au package ict/, puis en derive les dossiers de donnees.# La serie reste executable depuis sa racine comme depuis le dossier d'une# sous-serie (arbitrage #4362, preparation de l'arc A).import sysfrom pathlib import PathICT_ROOT = Path.cwd()whilenot (ICT_ROOT /"ict"/"__init__.py").exists() and ICT_ROOT != ICT_ROOT.parent: ICT_ROOT = ICT_ROOT.parentassert (ICT_ROOT /"ict"/"__init__.py").exists(), (f"package ict/ introuvable en remontant depuis {Path.cwd().name}")ifstr(ICT_ROOT) notin sys.path: sys.path.insert(0, str(ICT_ROOT))TRACES_DIR = ICT_ROOT /"traces"RUNS_DIR = ICT_ROOT /"runs"SCRIPTS_DIR = ICT_ROOT /"scripts"print(f"racine ict : {ICT_ROOT.name}")
racine ict : ICT-Series
import osimport sys# Generateurs conformes importes du module ict (plus de version inline).from ict.bench_factorise import Mess3Canonical, RRXORfrom ict.mixed_state import msp_mess3, msp_rrxorMESS3 = Mess3Canonical()RRXOR_GEN = RRXOR()def simulate_residual(B, dim, layer, rng):"""Simule des activations a partir d'une matrice de croyances B (N, K). Lineaire en B : X = B @ W ou W est (K, dim). Un belief Dirac sur l'etat i redonne X = W_i (le regime orthogonal de l'exercice 1 est le cas particulier croyance synchronisee). layer : 'pre' (bruit additif fort) ou 'post' (normalisation L2 + bruit faible, style LayerNorm). """ K = B.shape[1] W = rng.standard_normal((K, dim)) *0.5 X = B @ Wif layer =="pre": X += rng.standard_normal(X.shape) *0.3elif layer =="post": norms = np.linalg.norm(X, axis=1, keepdims=True) +1e-6 X = X / norms X += rng.standard_normal(X.shape) *0.05return X# Test rapide des generateurs conformesrng = np.random.default_rng(42)states_m, obs_m = MESS3.sample(100, int(rng.integers(0, 2**31-1)))states_r, obs_r = RRXOR_GEN.sample(99, int(rng.integers(0, 2**31-1)))print(f"Mess3 : 100 steps, etats uniques = {np.unique(states_m)}, obs uniques = {np.unique(obs_m)}")print(f"RRXOR : 99 steps, etats d'arrivee uniques = {np.unique(states_r)}")k = (len(obs_r) //3) *3print(f"RRXOR : triplets (r1, r2, r1 XOR r2) valides : {bool(np.all(obs_r[2:k:3] == obs_r[0:k:3] ^ obs_r[1:k:3]))}")
Mixed-state presentation : la geometrie exacte du banc
La primitive ict/mixed_state.py enumere par BFS l’arbre sequence -> croyance : cardinal par profondeur, union fermee, et le test fondateur de la dissociation — des croyances distinctes partagent la meme prediction next-token.
# Mixed-state presentation : enumeration BFS sequence -> croyance (#16225)# Mess3 : croissance 3^k. RRXOR : union FERMEE a 36 croyances distinctes.msp3 = msp_mess3(max_depth=4)mspr = msp_rrxor()print("MSP Mess3, croyances par profondeur :", [msp3.n_distinct(d) for d inrange(msp3.depth)])print("MSP RRXOR, croyances par profondeur :", [mspr.n_distinct(d) for d inrange(mspr.depth)])print(f"MSP RRXOR, union des croyances distinctes : {mspr.n_distinct_total()} (litterature : 36 = 31 transitoires + 5 recurrentes)")# Dissociation : des croyances DISTINCTES partagent la meme prediction next-tokenWsum = RRXOR_GEN.edge_tensor().sum(axis=1) # Wsum[s, y] = P(y | etat causal s)groups = {}for level in mspr.nodes:for b in level: pred =tuple(np.round(b @ Wsum, 6)) groups.setdefault(pred, set()).add(tuple(np.round(b, 6)))n_beliefs =sum(len(g) for g in groups.values())print(f"{n_beliefs} croyances pour {len(groups)} predictions next-token distinctes : la carte belief -> next-token est non injective")example =max(groups.values(), key=len)print(f"Groupe le plus large : {len(example)} croyances distinctes -> meme next-token (uniforme 1/2, 1/2)")ok3, f3 = msp3.verify_invariants(MESS3.beliefs)okr, fr = mspr.verify_invariants(RRXOR_GEN.beliefs)print(f"Invariants MSP Mess3 : {ok3}{f3}")print(f"Invariants MSP RRXOR : {okr}{fr}")
MSP Mess3, croyances par profondeur : [1, 3, 9, 27]
MSP RRXOR, croyances par profondeur : [1, 2, 4, 8, 12, 17, 17, 17]
MSP RRXOR, union des croyances distinctes : 36 (litterature : 36 = 31 transitoires + 5 recurrentes)
36 croyances pour 11 predictions next-token distinctes : la carte belief -> next-token est non injective
Groupe le plus large : 10 croyances distinctes -> meme next-token (uniforme 1/2, 1/2)
Invariants MSP Mess3 : True []
Invariants MSP RRXOR : True []
Exemple guide 1 - Regime orthogonal (sanity check)
Hypothese : sur des activations ou chaque etat cache correspond a une direction orthogonale dans le residual stream, un probe lineaire Ridge doit atteindre une accuracy held-out proche de 1.0, et le shuffle baseline doit rester a ~1/K (1/3 = 0.333).
C’est le regime trivial : on verifie que les primitives fonctionnent et que le protocole capture bien la linearite du belief. Tout ecart significatif constitue un bug dans les primitives ou le protocole.
Verdict attendu : H1 (accuracy_belief - accuracy_shuffle >= 0.3) SUPPORTED. H2 (pre-LN > post-LN) est une question ouverte : avec l’encodage lineaire en belief (post-#16225), la normalisation post-L2 n’ecrase plus l’echelle des directions – le sens se lit sur la mesure, pas sur une attente.
L’exemple guide 1 valide les primitives a DIM = 32. La limite 4 du verdict pose la question : a quelle largeur le sanity check tient-il encore ?
Enonce : faites varier la dimension du residual stream simule dans {2, 3, 5, 32} dans le regime orthogonal (croyance Dirac, probe pre-LN), et affichez l’accuracy held-out par dimension (moyenne puis ecart-type sur RNG_SEEDS). A partir de quelle largeur le verdict H1 (gap d’au moins 0.3 au-dessus du shuffle a 1/3) tient-il ?
Sortie attendue : une ligne par dimension avec accuracy et ecart-type, puis le verdict H1 par dimension.
Indices :
# Indice : simulate_residual(B, dim, "pre", rng) prend la dimension en argument – tout le reste du protocole de l’exemple guide 1 est inchange.
# Etape 1 : boucler sur les dimensions, reutiliser le corps de l’exemple guide 1 avec la dimension de la boucle a la place de DIM.
# Etape 2 : comparer chaque accuracy au shuffle (1/3) avec le seuil H1.
# Exercice 1 : largeur minimale du residual stream -- a completer# TODO etudiant : sweep de la dimension dans {2, 3, 5, 32} en regime orthogonal# (croyance Dirac, probe pre-LN) : accuracy held-out +/- ecart-type par dimension# sur RNG_SEEDS, puis verdict H1 (gap >= 0.3 au-dessus de 1/3) par dimension.print("Exercice a completer : accuracy du probe orthogonal par largeur de stream.")resultat =None# TODO etudiant
Exercice a completer : accuracy du probe orthogonal par largeur de stream.
Exemple guide 2 - Regime Mess3 canonique (emissions non revelatrices)
Le banc est desormais le Mess3 canonique (Marzen & Crutchfield 2017) : alphabet ternaire discret dont l’emission ne revele pas l’etat. Le belief ground-truth est la distribution filtree exacte P(s_t | obs_0..t) sur le 2-simplexe – calculee par MESS3.beliefs(obs) (filtration forward numpy).
Question : le probe lineaire recupere-t-il le belief vectoriel (coordonnees du simplexe) depuis le residual stream simule ?
Ce qui change vs la version obs = etat : l’ancienne equivalence next-token == belief par construction est LEVEE (c’etait l’artefact denonce par #16225 – accuracy 1.000 tautologique). Le probe next-token predira une observation stochastique : son plafond est E[max_y P(y_{t+1} | b_t)], mesure ci-dessous.
Exercice 2 - H2 sur le banc non trivial : pre-LN vs post-LN
L’exemple guide 1 mesurait H2 (pre-LN > post-LN) dans le regime orthogonal ; son enonce laissait la question ouverte ailleurs. Tranchez-la sur Mess3.
Enonce : pour le regime Mess3 canonique, mesurez le probe belief (accuracy argmax ET R2 sur les coordonnees du simplexe) en pre-LN et en post-LN, sur RNG_SEEDS. H2 est-elle SUPPORTED sur ce banc ?
Sortie attendue : accuracy et R2 pour chaque normalisation, puis le verdict H2 avec une phrase d’interpretation.
Indices :
# Indice : le changement est d’un seul argument – simulate_residual(beliefs, DIM, layer, rng) avec layer dans {“pre”, “post”}.
# Etape 1 : reprendre le probe belief de l’exemple guide 2 (regression Ridge sur les coordonnees du simplexe), une fois par layer.
# Etape 2 : calculer R2 comme dans l’exemple guide 2 (un moins le rapport des sommes de carres).
# Exercice 2 : pre-LN vs post-LN sur le probe belief Mess3 -- a completer# TODO etudiant : accuracy argmax et R2 du probe belief Mess3 en pre-LN et en# post-LN (RNG_SEEDS), puis verdict H2 (pre-LN > post-LN) sur ce banc.print("Exercice a completer : le probe belief Mess3 sous les deux normalisations.")resultat =None# TODO etudiant
Exercice a completer : le probe belief Mess3 sous les deux normalisations.
Exemple guide 3 - RRXOR conforme : dissociation belief vs next-token
Le RRXOR de la litterature (Riechers & Crutchfield 2018) repete les triplets (r1, r2, r1 XOR r2). Sa MSP compte 36 croyances distinctes, et la cellule de demo l’a montre : la carte belief -> next-token est non injective – des croyances distinctes partagent la meme prediction. C’est exactement la structure que l’ancien banc (parite du bit precedent, 2 etats) ne pouvait pas produire.
Protocole : le residual stream simule encode lineairement le belief vecteur (5 coordonnees). Le probe belief regresse ces coordonnees ; le probe next-token predit le bit suivant, stochastique depuis G/A (uniforme) et deterministe depuis X – plafond E[max_y P(y | b_t)] ~ 2/3 en regime stationnaire, mesure ci-dessous.
Prediction : le probe belief depasse le probe next-token d’au moins 0.1 (H3) – le belief porte la phase du processus, le next-token n’en porte qu’une projection. Un H3 NOT_SUPPORTED sur CE banc serait un vrai resultat (plus d’artefact de generateur a invoquer).
Exercice 3 - Robustesse au bruit du probe belief RRXOR
La limite 3 du verdict le nomme : le banc n’a explore qu’un bruit additif fixe. Quantifiez la robustesse du readout.
Enonce : ajoutez au residual stream simule (regime RRXOR, pre-LN) un bruit additif d’ecart-type sigma dans {0.0, 0.3, 1.0, 1.5, 2.0}, et mesurez l’accuracy held-out du probe belief par sigma. Entre quelles valeurs consecutives de sigma l’accuracy tombe-t-elle sous 0.9 ?
Sortie attendue : accuracy et ecart-type par sigma, puis l’encadrement de la rupture.
Indices :
# Etape 1 : apres X = simulate_residual(beliefs, DIM, "pre", rng), ajouter X = X + rng.standard_normal(X.shape) * sigma – le bruit frappe train ET test, c’est la robustesse du readout qui est mesuree.
# Etape 2 : reprendre le probe belief de l’exemple guide 3, la boucle sigma en plus de la boucle seed.
# Indice : la rupture attendue se situe entre deux valeurs consecutives du sweep – dire lesquelles suffit.
# Exercice 3 : robustesse au bruit du probe belief RRXOR -- a completer# TODO etudiant : sweep sigma dans {0.0, 0.3, 1.0, 1.5, 2.0} -- bruit additif sur le# stream apres simulate_residual (regime RRXOR, pre-LN) -- accuracy held-out du probe# belief par sigma, puis encadrement du sigma ou l'accuracy passe sous 0.9.print("Exercice a completer : la courbe de robustesse du probe belief RRXOR.")resultat =None# TODO etudiant
Exercice a completer : la courbe de robustesse du probe belief RRXOR.
Verdict global
Hypothese
Regime orthogonal (EG 1)
Mess3 canonique (EG 2)
RRXOR conforme (EG 3)
H1 belief >> shuffle
SUPPORTED si gap >= 0.3
SUPPORTED si gap >= 0.3
SUPPORTED si gap >= 0.2
H2 pre-LN > post-LN
applicable orthogonal
-
-
H3 belief >> next-token
-
plafond next-token mesure
SUPPORTED si dissociation >= 0.1
Lecture : - Le regime orthogonal valide les primitives : le probe Ridge recupere quasi-parfaitement le belief quand l’information est lineairement encodee. - Le regime Mess3 canonique applique le probe a un HMM dont l’observation ne revele pas l’etat : le belief est un point du simplexe, recupere par regression vectorielle (R2), et le probe next-token plafonne a E[max_y P(y|b)] mesure – l’equivalence tautologique de l’ancienne version obs = etat est levee (#16225). - Le regime RRXOR conforme teste la dissociation sur la structure de la litterature : 36 croyances distinctes dont plusieurs partagent la meme prediction next-token (MSP non injective, see demo). Le probe belief doit performer au-dela du plafond next-token.
Limites
Regime orthogonal est trivial : c’est un sanity check, pas un resultat scientifique. Il valide les primitives et le protocole.
Banc simule, pas transformer reel : simulate_residual encode lineairement le belief ; la migration vers des activations reelles (Epic #15475) reste le test decisif.
Bruit Gaussien additif : on n’a pas explore de regimes ou le bruit est structure (correle aux etats) ou non-stationnaire.
Dimension 32 : suffisant pour 3-5 etats caches ; pour des HMM plus larges (10+ etats), il faudrait augmenter DIM et possiblement utiliser un probe non-lineaire (mais ce notebook reste numpy-only).
Migration future
Quand le contrat de trace v1 (Epic #15475 instrument) sera livre, ce notebook pourra charger des activations reelles (NPZ) au lieu des activations simulees. La signature simulate_residual(B, dim, layer, rng) est compatible avec un futur load_real_activations(npz_path, layer).
Références
arXiv:2405.15943 — Shai et al., Transformers Represent Belief State Geometry in their Residual Stream : papier fondateur du théorème de géométrie belief-state linéairement représentée dans le residual stream ; §2.2 définit la mise à jour eta' = eta T^(x) / (eta T^(x) 1) et §3.2 le RRXOR à 36 états de croyance.
Marzen & Crutchfield 2017 — Nearly maximally predictive features and their dimensions, Phys. Rev. E 95(5):051301(R) : origine du processus Mess3 (correction d’attribution #16225 — l’ancienne mention « singh et al. 1994 » était erronée).
Riechers & Crutchfield 2017 — Spectral Simplicity of Apparent Complexity, Part II (arXiv:1706.00883) : définition du RRXOR (triplets r1, r2, r1 XOR r2), epsilon-machine à 5 états, S-MSP à 36 croyances (Fig. 4 et 7).
arXiv:2602.02385 — Transformers Learn Factored Representations : base de la réimplémentation numpy-only (régimes orthogonal / probes linéaires).
Dépôt ZM — Zeinab-Mohammadi/pytorch-AI-interpretability-transformer_ZM : architecture minimale de référence, point de comparaison pour la migration future vers des activations réelles (cf. Epic #15475).
print("="*60)print(f"VERDICT FINAL - {nb_name}")print("="*60)verdict_lines = []verdict_lines.append(f"EG 1 orthogonal : H1={'SUPPORTED'if H1_orth else'NOT_SUPPORTED'}, H2={'SUPPORTED'if H2_orth else'NOT_SUPPORTED'}")verdict_lines.append(f"EG 2 Mess3 canonique : H1={'SUPPORTED'if H1_mess3 else'NOT_SUPPORTED'}, R2 belief={mean_r2:.3f}, plafond next-token={mean_ceiling:.3f}")verdict_lines.append(f"EG 3 RRXOR conforme : H1={'SUPPORTED'if H1_rrxor else'NOT_SUPPORTED'}, H3={'SUPPORTED'if H3_rrxor else'NOT_SUPPORTED'}")for line in verdict_lines:print(line)if H1_orth and H1_mess3 and H1_rrxor:if H3_rrxor:print("\n-> Conclusion : SUPPORTED sur les hypotheses principales (H1, H3)")print(" Le probe lineaire recupere le belief state (vectoriel) de Mess3")print(" canonique et de RRXOR conforme ; la dissociation est SUPPORTED :")print(" le belief porte la phase du processus, le next-token n'en porte")print(" qu'une projection (plafond mesure, non un artefact du banc).")else:print("\n-> Conclusion : H1 SUPPORTED, H3 NOT_SUPPORTED")print(f" Dissociation mesuree : {dissociation:.3f} (seuil 0.1).")print(" Sur le banc conforme #16225 (MSP 36 croyances, croyances")print(" distinctes a next-token identique), ce resultat est un vrai")print(" resultat d'experience -- il n'y a plus de defaut de generateur")print(" a invoquer ; la cause serait du cote de l'encodage simule.")else:print("\n-> Conclusion : NOT_SUPPORTED sur au moins une hypothese - voir details ci-dessus.")
============================================================
VERDICT FINAL - ICT-37-FLens-BeliefState-Python
============================================================
EG 1 orthogonal : H1=SUPPORTED, H2=NOT_SUPPORTED
EG 2 Mess3 canonique : H1=SUPPORTED, R2 belief=0.886, plafond next-token=0.408
EG 3 RRXOR conforme : H1=SUPPORTED, H3=SUPPORTED
-> Conclusion : SUPPORTED sur les hypotheses principales (H1, H3)
Le probe lineaire recupere le belief state (vectoriel) de Mess3
canonique et de RRXOR conforme ; la dissociation est SUPPORTED :
le belief porte la phase du processus, le next-token n'en porte
qu'une projection (plafond mesure, non un artefact du banc).