Lean-12b — Théorème de Sensibilité de Huang (companion formel natif)

Ce notebook est le companion formel du notebook Lean-12-Sensitivity-Theorem (Python, qui calcule la sensibilité \(s(f)\) sur l’hypercube). Il exhibe la preuve formelle dans le lake [sensitivity_lean](sensitivity_lean

Position dans la série Lean

Lean-12b est un cas d’école d’intégration native d’un résultat SOTA en Lean 4 : - Lean-12 (notebook mainstream) implémente la sensibilité en Python — c’est l’ approche pragmatique où l’on calcule explicitement \(s(f)\) sur l’hypercube de dimension \(n\) et on observe la borne \(s(f) \le \sqrt{n}\). Lean fournit l’interpréteur Python pour valider empiriquement la conjecture. - Lean-12b (ce notebook) va plus loin : on compile réellement la preuve Huang 2019 dans le lake sensitivity_lean, on interroge le compilateur via #check et #print axioms, et on vérifie l’absence de sorry. C’est l’approche formelle : la conjecture est prouvée, pas seulement vérifiée sur cas.

Pourquoi les deux approches ensemble ? La première motive (pourquoi se soucier de la sensibilité ?), la seconde certifie (la borne est tenue pour toute fonction booléenne, pas seulement celles testées). Lean-6 (Mathlib) fournit le substrat commutatif ; Lean-12b montre la cérémonie d’un “vrai” théorème.

Le pont : Lean-12 (empirique) ↔︎ Lean-12b (formel) ↔︎ Lean-14 (Finiteness, autre bound polynomial) ↔︎ Lean-16 (Conway Free Will, autre théorème emblématique résolu formellement). Tous démontrent la même leçon : un notebook qui exhibe la preuve dans le kernel Lean est plus solide qu’un notebook qui la décrit en prose. Navigation : Lean-12 — Sensitivity (empirique Python) | Suivant : Lean-12c — TPR (companion natif) | Index de la série

1. Import du lake Sensitivity

Le lake exporte ses modules. L’import natif déclenche la résolution de la chaîne Mathlib (via la jonction locale).

Comment Lean 4 résout l’import : import Sensitivity déclenche la lecture du lakefile.toml du notebook courant (généré par Lean notebook setup), qui indique le chemin ..\\_target\deps\sensitivity_lean et la liste des dépendances Mathlib. Lean télécharge alors Mathlib (cache ~/.elan), compile les modules indiqués, et rend les namespaces visibles au kernel #check. C’est la même mécanique que Lean-6 (Mathlib) et Lean-9 (SK Multi-Agents), à la seule différence que sensitivity_lean est un lake tierce (sous lean_lakes/sensitivity_lean), pas un module Mathlib direct.

open Sensitivity rend le namespace Sensitivity.Huang.degree_theorem accessible comme Huang.degree_theorem (sans préfixe). C’est l’import idiomatique dans Lean 4 : on importe le namespace sélectivement pour ne pas polluer le contexte global avec les noms de Mathlib (Lean-6 recommande open scoped pour les namespace fermés, open pour les namespaces qu’on utilise massivement).

Le pont : la cérémonie import ... ; open ... apparaît dans Lean-6 pour toute utilisation Mathlib, dans Lean-9 pour les namespaces MultiAgent, et dans Lean-12b pour le lake Sensitivity. C’est la porte d’entrée standard.

import Sensitivity
open Sensitivity
import Sensitivity
open Sensitivity
--% env 0
Raw input {"cmd": "import Sensitivity\nopen Sensitivity"}
Raw output {"env": 0}

2. Vérification native — #check des théorèmes piliers

Plutôt qu’un grep de chaînes, on demande au compilateur les types réels.

Pourquoi #check plutôt que #print ? #print affiche le terme exact tel que stocké dans le module (corps de la preuve, tactiques utilisées, noms de lemmes). #check se contente de demander à Lean de typer le nom et d’afficher le type (signature) résultant. Pour le “est-ce que ça compile” et “quels arguments prend ce théorème”, #check est plus propre ; pour comprendre comment la preuve est construite, #print est nécessaire.

La cellule qui suit demande #check de 4 théorèmes : - huang_degree_theorem : le théorème phare (Huang 2019), lie \(\sqrt{m+1}\) au degré minimum d’un sous-ensemble > \(2^m\). Type : un énoncé Ens sur Q_{m+1}. - exists_eigenvalue : il existe un vecteur propre de \(f_n^2 = n \mathrm{Id}\). Type : existence vector. - f_squared : l’identité \(f^2 = n \mathrm{Id}\). Type : égalité d’application. - g_injective : la matrice de Knuth \(g_m\) est injective. Type : injectivité.

Ces 4 noms couvrent l’architecture de la preuve : il faut l’identité spectrale (f_squared), l’injectivité de la matrice auxiliaire (g_injective), un lemme d’existence spectrale (exists_eigenvalue), et le théorème final (huang_degree _theorem). Si Lean compile #check sans erreur, c’est que le module est cohérent ; #print axioms en §3 confirmera l’absence de sorry.

Le pont : #check est universel dans Lean-6 (Mathlib) et Lean-8 (Agentic Proving). Lean-14 (Finiteness) introduit #check avec arguments explicites pour désambiguïser les surcharges. Lean-16 (Conway Free Will) l’utilise sur les 16 axiomes originaux de Conway.

#check Sensitivity.huang_degree_theorem
#check Sensitivity.exists_eigenvalue
#check Sensitivity.f_squared
#check Sensitivity.g_injective
Sensitivity.huang_degree_theorem {m : ℕ} (H : Set (Q m.succ)) (hH : H.toFinset.card ≥ 2 ^ m + 1) : ∃ q ∈ H, √(↑m + 1) ≤ ↑(H ∩ q.adjacent).toFinset.card
Sensitivity.exists_eigenvalue {m : ℕ} (H : Set (Q m.succ)) (hH : H.toFinset.card ≥ 2 ^ m + 1) : ∃ y ∈ Submodule.span ℝ (e '' H) ⊓ (g m).range, y ≠ 0
Sensitivity.f_squared {n : ℕ} (v : V n) : (f n) ((f n) v) = ↑n • v
Sensitivity.g_injective {m : ℕ} : Function.Injective ⇑(g m)
--% env 1
Raw input {"cmd": "#check Sensitivity.huang_degree_theorem\n#check Sensitivity.exists_eigenvalue\n#check Sensitivity.f_squared\n#check Sensitivity.g_injective", "env": 0}
Raw output {"messages": [{"severity": "info", "pos": {"line": 1, "column": 0}, "endPos": {"line": 1, "column": 6}, "data": "Sensitivity.huang_degree_theorem {m : ℕ} (H : Set (Q m.succ)) (hH : H.toFinset.card ≥ 2 ^ m + 1) :\n ∃ q ∈ H, √(↑m + 1) ≤ ↑(H ∩ q.adjacent).toFinset.card"}, {"severity": "info", "pos": {"line": 2, "column": 0}, "endPos": {"line": 2, "column": 6}, "data": "Sensitivity.exists_eigenvalue {m : ℕ} (H : Set (Q m.succ)) (hH : H.toFinset.card ≥ 2 ^ m + 1) :\n ∃ y ∈ Submodule.span ℝ (e '' H) ⊓ (g m).range, y ≠ 0"}, {"severity": "info", "pos": {"line": 3, "column": 0}, "endPos": {"line": 3, "column": 6}, "data": "Sensitivity.f_squared {n : ℕ} (v : V n) : (f n) ((f n) v) = ↑n • v"}, {"severity": "info", "pos": {"line": 4, "column": 0}, "endPos": {"line": 4, "column": 6}, "data": "Sensitivity.g_injective {m : ℕ} : Function.Injective ⇑(g m)"}], "env": 1}

Preuve sans sorry — #print axioms

Le théorème phare ne dépend que des 3 axiomes standards de Lean (pas de sorryAx), ce qui prouve que la preuve est complète (sans sorry).

Trois axiomes standards de Lean 4 : 1. propext : l’extensionnalité des propositions — si \(p \leftrightarrow q\) et \(a : p\), alors on peut transporter \(a\) vers \(q\). C’est l’axiome de remplacement pour les types de propositions. 2. Classical.choice : pour toute famille \(p : \alpha \to \mathrm{Prop}\), on peut choisir un \(x : \alpha\) tel que \(p(x)\). C’est l’axiome non-constructif qui autorise les preuves par choix. 3. Quot.sound : les types quotient respectent la relation d’équivalence — si \(a \sim b\), alors $\sim$.out a = b$ au sens où le quotient force l’égalité.

sorryAx est interdit : il marque les preuves qui ont un trou sorry en elles. Voir #print axioms pour Huang 2019 : si sorryAx apparaît, le théorème est incomplet ; seule l’absence confirme que la preuve est close.

Pourquoi #print axioms est la preuve** de complétude ?** Parce qu’il récupère récursivement les axiomes utilisés dans la chaîne d’imports et de preuves sur lesquelles repose le théorème. Si le théorème utilise un lemme qui contient sorry, #print axioms le verrait — il n’y a aucun moyen de cacher un sorry à cette commande.

Vérification positive : Lean-3 (Propositions/Proofs) introduit #print axioms sur des preuves simples. Lean-6 (Mathlib) l’utilise comme garde-fou. Lean-16 (Conway Free Will) l’étend aux preuves multimodales. Lean-12b est l’archétype de la cérémonie : on vérifie le théorème phare ET un lemme intermédiaire (f_squared) pour montrer la cohérence de l’ensemble.

Le pont : #print axioms est le test de complétude. Lean-12b documente le pattern, Lean-14 l’applique systématiquement, Lean-16 le couple avec #guard pour interdire sorry dans les modules production.

#print axioms Sensitivity.huang_degree_theorem
#print axioms Sensitivity.f_squared
'Sensitivity.huang_degree_theorem' depends on axioms: [propext, Classical.choice, Quot.sound]
'Sensitivity.f_squared' depends on axioms: [propext, Classical.choice, Quot.sound]
--% env 2
Raw input {"cmd": "#print axioms Sensitivity.huang_degree_theorem\n#print axioms Sensitivity.f_squared", "env": 1}
Raw output {"messages": [{"severity": "info", "pos": {"line": 1, "column": 0}, "endPos": {"line": 1, "column": 6}, "data": "'Sensitivity.huang_degree_theorem' depends on axioms: [propext, Classical.choice, Quot.sound]"}, {"severity": "info", "pos": {"line": 2, "column": 0}, "endPos": {"line": 2, "column": 6}, "data": "'Sensitivity.f_squared' depends on axioms: [propext, Classical.choice, Quot.sound]"}], "env": 2}

3. Arc pédagogique — la stratégie de preuve de Huang (2019)

La sensitivity conjecture dit que pour toute fonction booléenne \(f: Q_n \to \{0,1\}\), sa sensibilité \(s(f)\) (nombre de voisins de l’hypercube où \(f\) change) est majorée par un polynôme en \(n\). Huang prouve la borne optimale.

L’arc en 4 sous-sections : on présente d’abord le langage ( espaces vectoriels, dualité), puis l’opérateur (\(f_n^2 = n\mathrm{Id}\)), puis le théorème principal (Huang 2019). La cellule 3.5 (conclue en prose) résume l’apport.

Pourquoi cette structure en 4 ? C’est la progression pédagogique standard des notebooks Lean : (1) vocabulaire → (2) lemme clé → (3) théorème → (4) portée. Lean-12 (Sensitivity, mainstream) suit la même structure mais en Python. Lean-14 (Finiteness Derivatives) et Lean-16 (Conway Free Will) la reprennent — c’est un pattern de la série Lean-1..6 / Lean-12 / Lean-14 / Lean-16.

Le pont : Lean-12 expose la conjecture en Python (empirique). Lean-12b la prouve en Lean (formel). Lean-14 montre qu’un autre théorème emblématique (la borner de dérivées de fonctions booléennes) suit le même arc. Lean-16 reformule le théorème de Conway-Kochen (libre arbitre) selon cette grille.

#check Sensitivity.Q
#check Sensitivity.π
#check Sensitivity.Q.adjacent
#check Sensitivity.Q.card
Sensitivity.Q (n : ℕ) : Type
Sensitivity.π {n : ℕ} : Q n.succ → Q n
Sensitivity.Q.adjacent {n : ℕ} (p : Q n) : Set (Q n)
Sensitivity.Q.card (n : ℕ) : Fintype.card (Q n) = 2 ^ n
--% env 3
Raw input {"cmd": "#check Sensitivity.Q\n#check Sensitivity.\u03c0\n#check Sensitivity.Q.adjacent\n#check Sensitivity.Q.card", "env": 2}
Raw output {"messages": [{"severity": "info", "pos": {"line": 1, "column": 0}, "endPos": {"line": 1, "column": 6}, "data": "Sensitivity.Q (n : ℕ) : Type"}, {"severity": "info", "pos": {"line": 2, "column": 0}, "endPos": {"line": 2, "column": 6}, "data": "Sensitivity.π {n : ℕ} : Q n.succ → Q n"}, {"severity": "info", "pos": {"line": 3, "column": 0}, "endPos": {"line": 3, "column": 6}, "data": "Sensitivity.Q.adjacent {n : ℕ} (p : Q n) : Set (Q n)"}, {"severity": "info", "pos": {"line": 4, "column": 0}, "endPos": {"line": 4, "column": 6}, "data": "Sensitivity.Q.card (n : ℕ) : Fintype.card (Q n) = 2 ^ n"}], "env": 3}

3.2 Espace vectoriel libre \(V_n\) — l’algèbre linéaire

\(V_n\) est l’espace vectoriel libre sur \(Q_n\) (dimension \(2^n\)), e la base canonique, \varepsilon la base duale. Le lemme de dualité \(\varepsilon_p(e_q) = [p=q]\) est le cœur combinatoire.

Pourquoi \(V_n\) est en dimension \(2^n\) ? L’hypercube \(Q_n\) a \(2^n\) sommets, et \(V_n\) est l’espace vectoriel libre sur \(Q_n\), donc \(\dim V_n = |Q_n| = 2^n\). Cette explosion exponentielle est ce qui rend la preuve a priori coûteuse ; la magie de Huang est de la contourner via le rayon spectral de \(f_n\). Lean-6 (Mathlib) fournit Finsupp, Basis, et la dualité canonique ; Lean-12b les instancie pour \(Q_n\).

Démonstration de la dualité : \(\varepsilon\) est définie par \varepsilon_p(e_q) = 1 si \(p = q\), 0 sinon. C’est la définition fonctionnelle de la base duale en algèbre linéaire. Dans Lean, on code cela via Finsupp.apply ou via Pi.single appliqué à p. La cellule #check qui suit vérifie que ces constructions sont bien typées.

Le pont : \(V_n\) et la dualité apparaissent dans Lean-6 (Mathlib / LinearAlgebra. Dual), Lean-8 (Agentic Proving) pour la sémantique des prédicats, et Lean-14 (Finiteness) pour le calcul différentiel booléen. Lean-12b est leur instantiation sur \(Q_n\). Voir aussi Lean-16d (Conway-Game-of-Life Native) qui réemploie la dualité pour les patterns Game-of-Life.

#check Sensitivity.V
#check Sensitivity.e
#check Sensitivity.ε
#check Sensitivity.duality
Sensitivity.V : ℕ → Type
Sensitivity.e {n : ℕ} : Q n → V n
Sensitivity.ε {n : ℕ} : Q n → V n →ₗ[ℝ] ℝ
Sensitivity.duality {n : ℕ} (p q : Q n) : (ε p) (e q) = if p = q then 1 else 0
--% env 4
Raw input {"cmd": "#check Sensitivity.V\n#check Sensitivity.e\n#check Sensitivity.\u03b5\n#check Sensitivity.duality", "env": 3}
Raw output {"messages": [{"severity": "info", "pos": {"line": 1, "column": 0}, "endPos": {"line": 1, "column": 6}, "data": "Sensitivity.V : ℕ → Type"}, {"severity": "info", "pos": {"line": 2, "column": 0}, "endPos": {"line": 2, "column": 6}, "data": "Sensitivity.e {n : ℕ} : Q n → V n"}, {"severity": "info", "pos": {"line": 3, "column": 0}, "endPos": {"line": 3, "column": 6}, "data": "Sensitivity.ε {n : ℕ} : Q n → V n →ₗ[ℝ] ℝ"}, {"severity": "info", "pos": {"line": 4, "column": 0}, "endPos": {"line": 4, "column": 6}, "data": "Sensitivity.duality {n : ℕ} (p q : Q n) : (ε p) (e q) = if p = q then 1 else 0"}], "env": 4}

3.3 Opérateur spectral \(f_n\) — le cœur algébrique

Huang définit \(f_n : V_n \to V_n\) linéaire avec la propriété spectrale clé :

\[f_n^2 = n \cdot \mathrm{Id}\]

(donc les valeurs propres de \(f_n\) sont \(\pm\sqrt{n}\)). La matrice \(g_m\) de Knuth amène une valeur propre \(\sqrt{m+1}\) via f_image_g

Pourquoi \(f_n^2 = n \cdot \mathrm{Id}\) est le cœur ? Toute matrice \(A\) vérifiant \(A^2 = c I\) a pour valeurs propres les racines carrées de \(c\) (ici \(\pm\sqrt{n}\), avec multiplicité). Le rayon spectral \(\rho(f_n)\) est donc \(\sqrt{n}\), ce qui est la borne supérieure de \(s(f)\). C’est ce que Huang utilise pour borner la sensibilité.

Pourquoi g_m (Knuth) ? Knuth a introduit cette matrice dans “The Art of Computer Programming, Vol. 4A” comme un auxiliaire combinatoire. Sa propriété spectrale (valeur propre \(\sqrt{m+1}\)) est précisément ce qui connecte le spectre de \(f_m\) à la borne \(s(f) \le \sqrt{n}\). Le lemme f_image_g code cette connexion ; il prend \(f\) et \(g\) et produit un vecteur propre.

Vérification #check : Lean-12b vérifie les 4 noms (f, f_squared, g, f_image_g). Si #check réussit, c’est que les types sont définis et cohérents avec \(V_n\) et \(Q_m\). Le corps de la preuve utilise ces lemmes sans s’inquiéter de leur typage.

Le pont : l’identité spectrale \(A^2 = c I\) est un grand classique de l’algèbre linéaire. Lean-6 (Mathlib / Matrix) la généralise via Matrix.IsSymmetric et Matrix.IsPositive. Lean-14 (Finiteness) l’instancie pour le Laplacien discret. Lean-16 (Conway Free Will) sur des endomorphismes sur \(\mathbb{F}_2\).

#check Sensitivity.f
#check Sensitivity.f_squared
#check Sensitivity.g
#check Sensitivity.f_image_g
Sensitivity.f (n : ℕ) : V n →ₗ[ℝ] V n
Sensitivity.f_squared {n : ℕ} (v : V n) : (f n) ((f n) v) = ↑n • v
Sensitivity.g (m : ℕ) : V m →ₗ[ℝ] V m.succ
Sensitivity.f_image_g {m : ℕ} (w : V m.succ) (hv : ∃ v, (g m) v = w) : (f m.succ) w = √(↑m + 1) • w
--% env 5
Raw input {"cmd": "#check Sensitivity.f\n#check Sensitivity.f_squared\n#check Sensitivity.g\n#check Sensitivity.f_image_g", "env": 4}
Raw output {"messages": [{"severity": "info", "pos": {"line": 1, "column": 0}, "endPos": {"line": 1, "column": 6}, "data": "Sensitivity.f (n : ℕ) : V n →ₗ[ℝ] V n"}, {"severity": "info", "pos": {"line": 2, "column": 0}, "endPos": {"line": 2, "column": 6}, "data": "Sensitivity.f_squared {n : ℕ} (v : V n) : (f n) ((f n) v) = ↑n • v"}, {"severity": "info", "pos": {"line": 3, "column": 0}, "endPos": {"line": 3, "column": 6}, "data": "Sensitivity.g (m : ℕ) : V m →ₗ[ℝ] V m.succ"}, {"severity": "info", "pos": {"line": 4, "column": 0}, "endPos": {"line": 4, "column": 6}, "data": "Sensitivity.f_image_g {m : ℕ} (w : V m.succ) (hv : ∃ v, (g m) v = w) : (f m.succ) w = √(↑m + 1) • w"}], "env": 5}

3.4 Théorème principal — Huang 2019

Le théorème phare : tout sous-ensemble \(H\) de \(Q_{m+1}\) de taille \(> 2^m\) contient un sommet de degré \(\ge \sqrt{m+1}\). Par contraposition, cela donne \(s(f) \le \sqrt{n}\).

  • exists_eigenvalue : il existe un vecteur propre non nul dans le sous-espace enge
    • Décomposition : \(f_n^2 = n \mathrm{Id}\) + Cauchy-Schwarz sur \(g_m\) donnent le vecteur propre de \(f_m^2\) restreint à \(\mathrm{Im}(g)\).
  • huang_degree_theorem : la borne combinatoire sur \(\mathrm{Im}(g)\). Type
    un \(\forall\) sur les sous-ensembles \(H\) de \(Q_{m+1}\).

Pourquoi la contraposition ? La conjecture dit \(s(f) \le \sqrt{n}\) pour tout \(f\). Huang la démontre par contraposition : si \(s(f) > \sqrt{n}\), alors aucune borne spectrale n’est possible. C’est l’inverse logique : on suppose le pire cas et on exhibe un sous-ensemble \(H\) dont le degré est \(\ge \sqrt{m+1}\). Le lemme exists_eigenvalue est la brique technique qui rend la contraposition explicite.

Structure de la preuve (résumé) : 1. Soit \(H \subseteq Q_{m+1}\), \(|H| > 2^m\). 2. Soit \(\pi : Q_m \to Q_{m+1}\) l’injection canonique. Le sous-espace \(\mathrm{Im}(\pi)\) a dimension \(2^m < |H|\). 3. La matrice \(g_m\) envoie \(\mathbb{R}^{Q_{m+1}}\) dans \(\mathbb{R}^{Q_m + 1}\). 4. Par dimension, \(\mathrm{Ker}(g_m)\) intersecte le sous-espace engendré par \(H\) en un vecteur non nul. 5. Le vecteur propre est de degré \(\ge \sqrt{m+1}\) grâce à f_image_g.

C’est la chaîne d’inférences. Lean-12b cache la chaîne derrière exists_eigenvalue et huang_degree_theorem, ce qui rend le théorème utilisable sans avoir à re-pénétrer le raisonnement.

Le pont : la structure contraposée est empruntée à Lean-14 (Finiteness) et Lean-16 (Conway Free Will). Lean-8 (Agentic Proving) l’utilise pour les tactiques automatisées. Lean-6 (Mathlib) la généralise dans Mathlib.Order.PFilter.

#check Sensitivity.exists_eigenvalue
#check Sensitivity.huang_degree_theorem
Sensitivity.exists_eigenvalue {m : ℕ} (H : Set (Q m.succ)) (hH : H.toFinset.card ≥ 2 ^ m + 1) : ∃ y ∈ Submodule.span ℝ (e '' H) ⊓ (g m).range, y ≠ 0
Sensitivity.huang_degree_theorem {m : ℕ} (H : Set (Q m.succ)) (hH : H.toFinset.card ≥ 2 ^ m + 1) : ∃ q ∈ H, √(↑m + 1) ≤ ↑(H ∩ q.adjacent).toFinset.card
--% env 6
Raw input {"cmd": "#check Sensitivity.exists_eigenvalue\n#check Sensitivity.huang_degree_theorem", "env": 5}
Raw output {"messages": [{"severity": "info", "pos": {"line": 1, "column": 0}, "endPos": {"line": 1, "column": 6}, "data": "Sensitivity.exists_eigenvalue {m : ℕ} (H : Set (Q m.succ)) (hH : H.toFinset.card ≥ 2 ^ m + 1) :\n ∃ y ∈ Submodule.span ℝ (e '' H) ⊓ (g m).range, y ≠ 0"}, {"severity": "info", "pos": {"line": 2, "column": 0}, "endPos": {"line": 2, "column": 6}, "data": "Sensitivity.huang_degree_theorem {m : ℕ} (H : Set (Q m.succ)) (hH : H.toFinset.card ≥ 2 ^ m + 1) :\n ∃ q ∈ H, √(↑m + 1) ≤ ↑(H ∩ q.adjacent).toFinset.card"}], "env": 6}

4. Du retournement local à la masse spectrale

Les modules Fourier.lean ajoutés au lake relient cinq niveaux qui doivent être lus comme une seule chaîne de preuve :

  1. flip retourne une coordonnée et flip_flip montre que ce changement est involutif ;
  2. χ_flip et fourierCoeff_flip décrivent la covariance des caractères de Walsh et de leurs coefficients ;
  3. parseval conserve exactement l’énergie, sous une forme entière non normalisée ;
  4. fourierCoeff_discreteDerivative et flip_energy transforment la dérivée discrète en filtre spectral ;
  5. influence_spectral_mass identifie enfin le comptage combinatoire des changements à la masse des coefficients dont le support contient la coordonnée.

La normalisation est portée à gauche par le facteur \(2^n\) : toutes les identités vivent dans \(\mathbb{Z}\), sans division ni approximation numérique. La dernière partie de la cellule contrôle aussi le certificat fini en dimension 2 : des poids ternaires de Walsh reconstruisent exactement AND, puis NAND par complément du signe.

La cellule suivante interroge les types réellement exportés par le lake et les axiomes des trois maillons centraux. Elle ne reconstitue pas les preuves en prose : le kernel Lean est l’autorité.

#check Sensitivity.flip_flip
#check Sensitivity.χ_flip
#check Sensitivity.fourierCoeff_flip
#check Sensitivity.parseval
#check Sensitivity.fourierCoeff_discreteDerivative
#check Sensitivity.flip_energy
#check Sensitivity.influence_spectral_mass
#print axioms Sensitivity.fourierCoeff_flip
#print axioms Sensitivity.parseval
#print axioms Sensitivity.influence_spectral_mass
#check Sensitivity.WalshCertificate.weight_is_ternary
#check Sensitivity.WalshCertificate.score_and
#check Sensitivity.WalshCertificate.score_sign_is_and
#check Sensitivity.WalshCertificate.score_sign_is_nand
Sensitivity.flip_flip {n : ℕ} (x : Q n) (i : Fin n) : Sensitivity.flip (Sensitivity.flip x i) i = x
Sensitivity.χ_flip {n : ℕ} (S : Finset (Fin n)) (x : Q n) (i : Fin n) : χ S (Sensitivity.flip x i) = χ S x * if i ∈ S then -1 else 1
Sensitivity.fourierCoeff_flip {n : ℕ} (f : Q n → ℤ) (i : Fin n) (S : Finset (Fin n)) : fourierCoeff (fun x => f (Sensitivity.flip x i)) S = if i ∈ S then -fourierCoeff f S else fourierCoeff f S
Sensitivity.parseval {n : ℕ} (f g : Q n → ℤ) : 2 ^ n * ∑ x, f x * g x = ∑ S, fourierCoeff f S * fourierCoeff g S
Sensitivity.fourierCoeff_discreteDerivative {n : ℕ} (f : Q n → ℤ) (i : Fin n) (S : Finset (Fin n)) : fourierCoeff (fun x => f x - f (Sensitivity.flip x i)) S = if i ∈ S then 2 * fourierCoeff f S else 0
Sensitivity.flip_energy {n : ℕ} (f : Q n → ℤ) (i : Fin n) : 2 ^ n * ∑ x, (f x - f (Sensitivity.flip x i)) * (f x - f (Sensitivity.flip x i)) = 4 * ∑ S, if i ∈ S then fourierCoeff f S * fourierCoeff f S else 0
Sensitivity.influence_spectral_mass {n : ℕ} (F : Q n → Bool) (i : Fin n) : 2 ^ n * influence F i = ∑ S, if i ∈ S then fourierCoeff (fun x => ξ (F x)) S * fourierCoeff (fun x => ξ (F x)) S else 0
'Sensitivity.fourierCoeff_flip' depends on axioms: [propext, Classical.choice, Quot.sound]
'Sensitivity.parseval' depends on axioms: [propext, Classical.choice, Quot.sound]
'Sensitivity.influence_spectral_mass' depends on axioms: [propext, Classical.choice, Quot.sound]
Sensitivity.WalshCertificate.weight_is_ternary (S : Finset (Fin 2)) : WalshCertificate.weight S = -1 ∨ WalshCertificate.weight S = 0 ∨ WalshCertificate.weight S = 1
Sensitivity.WalshCertificate.score_and (x : Q 2) : WalshCertificate.score x = if (x 0 && x 1) = true then -2 else 2
Sensitivity.WalshCertificate.score_sign_is_and (x : Q 2) : decide (WalshCertificate.score x ≤ -1) = WalshCertificate.gateAnd (x 0) (x 1)
Sensitivity.WalshCertificate.score_sign_is_nand (x : Q 2) : decide (-1 < WalshCertificate.score x) = WalshCertificate.gateNand (x 0) (x 1)
--% env 7
Raw input {"cmd": "#check Sensitivity.flip_flip\n#check Sensitivity.\u03c7_flip\n#check Sensitivity.fourierCoeff_flip\n#check Sensitivity.parseval\n#check Sensitivity.fourierCoeff_discreteDerivative\n#check Sensitivity.flip_energy\n#check Sensitivity.influence_spectral_mass\n#print axioms Sensitivity.fourierCoeff_flip\n#print axioms Sensitivity.parseval\n#print axioms Sensitivity.influence_spectral_mass\n#check Sensitivity.WalshCertificate.weight_is_ternary\n#check Sensitivity.WalshCertificate.score_and\n#check Sensitivity.WalshCertificate.score_sign_is_and\n#check Sensitivity.WalshCertificate.score_sign_is_nand", "env": 6}
Raw output {"messages": [{"severity": "info", "pos": {"line": 1, "column": 0}, "endPos": {"line": 1, "column": 6}, "data": "Sensitivity.flip_flip {n : ℕ} (x : Q n) (i : Fin n) : Sensitivity.flip (Sensitivity.flip x i) i = x"}, {"severity": "info", "pos": {"line": 2, "column": 0}, "endPos": {"line": 2, "column": 6}, "data": "Sensitivity.χ_flip {n : ℕ} (S : Finset (Fin n)) (x : Q n) (i : Fin n) :\n χ S (Sensitivity.flip x i) = χ S x * if i ∈ S then -1 else 1"}, {"severity": "info", "pos": {"line": 3, "column": 0}, "endPos": {"line": 3, "column": 6}, "data": "Sensitivity.fourierCoeff_flip {n : ℕ} (f : Q n → ℤ) (i : Fin n) (S : Finset (Fin n)) :\n fourierCoeff (fun x => f (Sensitivity.flip x i)) S = if i ∈ S then -fourierCoeff f S else fourierCoeff f S"}, {"severity": "info", "pos": {"line": 4, "column": 0}, "endPos": {"line": 4, "column": 6}, "data": "Sensitivity.parseval {n : ℕ} (f g : Q n → ℤ) : 2 ^ n * ∑ x, f x * g x = ∑ S, fourierCoeff f S * fourierCoeff g S"}, {"severity": "info", "pos": {"line": 5, "column": 0}, "endPos": {"line": 5, "column": 6}, "data": "Sensitivity.fourierCoeff_discreteDerivative {n : ℕ} (f : Q n → ℤ) (i : Fin n) (S : Finset (Fin n)) :\n fourierCoeff (fun x => f x - f (Sensitivity.flip x i)) S = if i ∈ S then 2 * fourierCoeff f S else 0"}, {"severity": "info", "pos": {"line": 6, "column": 0}, "endPos": {"line": 6, "column": 6}, "data": "Sensitivity.flip_energy {n : ℕ} (f : Q n → ℤ) (i : Fin n) :\n 2 ^ n * ∑ x, (f x - f (Sensitivity.flip x i)) * (f x - f (Sensitivity.flip x i)) =\n 4 * ∑ S, if i ∈ S then fourierCoeff f S * fourierCoeff f S else 0"}, {"severity": "info", "pos": {"line": 7, "column": 0}, "endPos": {"line": 7, "column": 6}, "data": "Sensitivity.influence_spectral_mass {n : ℕ} (F : Q n → Bool) (i : Fin n) :\n 2 ^ n * influence F i =\n ∑ S, if i ∈ S then fourierCoeff (fun x => ξ (F x)) S * fourierCoeff (fun x => ξ (F x)) S else 0"}, {"severity": "info", "pos": {"line": 8, "column": 0}, "endPos": {"line": 8, "column": 6}, "data": "'Sensitivity.fourierCoeff_flip' depends on axioms: [propext, Classical.choice, Quot.sound]"}, {"severity": "info", "pos": {"line": 9, "column": 0}, "endPos": {"line": 9, "column": 6}, "data": "'Sensitivity.parseval' depends on axioms: [propext, Classical.choice, Quot.sound]"}, {"severity": "info", "pos": {"line": 10, "column": 0}, "endPos": {"line": 10, "column": 6}, "data": "'Sensitivity.influence_spectral_mass' depends on axioms: [propext, Classical.choice, Quot.sound]"}, {"severity": "info", "pos": {"line": 11, "column": 0}, "endPos": {"line": 11, "column": 6}, "data": "Sensitivity.WalshCertificate.weight_is_ternary (S : Finset (Fin 2)) :\n WalshCertificate.weight S = -1 ∨ WalshCertificate.weight S = 0 ∨ WalshCertificate.weight S = 1"}, {"severity": "info", "pos": {"line": 12, "column": 0}, "endPos": {"line": 12, "column": 6}, "data": "Sensitivity.WalshCertificate.score_and (x : Q 2) : WalshCertificate.score x = if (x 0 && x 1) = true then -2 else 2"}, {"severity": "info", "pos": {"line": 13, "column": 0}, "endPos": {"line": 13, "column": 6}, "data": "Sensitivity.WalshCertificate.score_sign_is_and (x : Q 2) :\n decide (WalshCertificate.score x ≤ -1) = WalshCertificate.gateAnd (x 0) (x 1)"}, {"severity": "info", "pos": {"line": 14, "column": 0}, "endPos": {"line": 14, "column": 6}, "data": "Sensitivity.WalshCertificate.score_sign_is_nand (x : Q 2) :\n decide (-1 < WalshCertificate.score x) = WalshCertificate.gateNand (x 0) (x 1)"}], "env": 7}

Lecture du résultat — une identité exacte, pas une analogie

La sortie du kernel doit rendre trois faits indépendants mais articulés :

  • le retournement de i multiplie un caractère de Walsh par -1 exactement lorsque i ∈ S, puis la même covariance se transporte aux coefficients ;
  • la dérivée discrète annule les fréquences ne contenant pas i et double les autres ; Parseval explique alors le facteur d’énergie 4 ;
  • influence_spectral_mass relie un entier de comptage à une somme de carrés spectraux, avec le facteur de normalisation 2 ^ n explicitement conservé.

Les lignes #print axioms doivent montrer l’empreinte standard [propext, Classical.choice, Quot.sound], sans sorryAx. Le certificat final est plus concret : weight_is_ternary borne chaque poids à {-1, 0, 1}, score_and reconstruit la table de vérité en dimension 2, et les deux théorèmes de signe certifient les compositions AND et NAND.

Cette section ne prouve pas qu’un modèle neuronal implémente spontanément une transformée de Walsh. Elle établit seulement, dans le noyau Lean, les identités finies utilisées pour analyser ou certifier une représentation spectrale booléenne.

5. Exercices

Exercice 1 — Sensibilité en Python

La sensibilité \(s(f)\) d’une fonction booléenne \(f: Q_n \to \{0,1\}\) est le maximum, sur les sommets \(x\), du nombre de voisins \(y\) de \(x\) avec \(f(y) \ne f(x)\). Complétez la fonction ci-dessous (en Python, hors du kernel Lean — cellule markdown

Méthode suggérée : - Énumérer toutes les paires \((x, y)\) voisines dans l’hypercube. - Pour chaque \(x\), compter les \(y\) voisins avec \(f(y) \ne f(x)\). C’est la sensibilité locale \(s(f, x)\). - Retourner \(\max_x s(f, x)\). C’est la sensibilité globale \(s(f)\).

Pour vérifier, vous pouvez importer ce notebook depuis Python en sous-process et comparer le résultat à Lean-12 (Sensitivity mainstream).

Pièges : - Ne pas oublier que deux sommets peuvent être voisins par plusieurs arêtes (mais pas pour l’hypercube simple : 1 seul axe par voisin). - Le retour f(x) != f(y) vs f(x) ^ f(y) : sur des booléens, c’est pareil, mais pour rester portable utilisez ^.

Le pont : cet exercice est l’instance directe du théorème Huang 2019. Lean-12 (Sensitivity mainstream) implémente cette fonction pour vérifier empiriquement la borne. Lean-14 (Finiteness) étend aux dérivées booléennes d’ordre supérieur.

Exercice 2 — Nilpotence de \(f\)

Montrez (sur papier, puis tentez en Lean) que la propriété \(f_n^2 = n \cdot \mathrm{Id}\) implique que \(f_n\) est diagonalisable sur \(\mathbb{R}\) avec valeurs propres \(\pm\sqrt{n}\). Indice : polynôme minimal \(X^2 - n\).

-- TODO etudiant : énoncé formel de la preuve

Méthode : montrer d’abord que \(X^2 - n\) annule \(f_n\) au sens de la multiplication des endomorphismes. En algèbre linéaire, une matrice \(A\) satisfaisant un polynôme scindé à racines simples est diagonalisable. Ici \(X^2 - n = (X - \sqrt{n})(X + \sqrt{n})\), racines simples (\(\sqrt{n} \ne -\sqrt{n}\) pour \(n > 0\)).

Tactiques Lean disponibles : - Matrix.IsSymmetric (Lean-6 / Mathlib) pour les endomorphismes symétriques. - Polynomial.IsSplittingField (Lean-6) pour la décomposition en facteurs. - Module.End.exists_eigenvalue (Lean-6) pour la diagonalisation sur les algèbres closes.

Sur le papier, c’est une démonstration de cours. En Lean, c’est une formalisation mécanique. Lean-12b attend que vous l’écriviez — c’est l’espace de pratique du companion.

Le pont : la diagonalisation via le polynôme minimal est un grand classique de l’algèbre linéaire abstraite. Lean-6 (Mathlib / LinearAlgebra.Eigenspace) en fournit les briques. Lean-14 (Finiteness Derivatives) l’instancie pour les endomorphismes de différences finies. Lean-16d (Conway-Game-of-Life Lean Native) l’utilise pour les shifts sur l’espace des configurations.

Exercice 3 — Vérifier la borne numérique

Pour \(n=4\), énumérez toutes les \(2^4 = 16\) fonctions de \(Q_4 \to \{0,1\}\) d’une variable pertinente et confirmez \(s(f) \le \sqrt{4} = 2\) sur les cas extrêmes (fonction majorité, parité).

from math import isqrt
# TODO etudiant : confirmer s(f) <

Méthode suggérée : - Énumérer les \(2^4 = 16\) entrées en utilisant product ou un masque binaire de 4 bits. - Pour chaque \(f\), calculer \(s(f) = \max_x s(f, x)\). - Identifier les cas extrêmes : parité (xor des 4 bits), majorité (somme \(> 2\)), constante (0 ou 1).

Validation empirique vs formelle : Lean-12 (Sensitivity mainstream) calcule \(s(f)\) exactement sur \(Q_n\) jusqu’à \(n = 6\) en Python. Lean-12b prouve la borne \(\sqrt{n}\) pour tout \(f\) en Lean 4. Les deux convergent : borne empirique sur \(Q_4\) est \(\sqrt{4} = 2\), et Lean-12b le prouve pour tout \(n\). Si votre calcul Python donne autre chose, c’est un bug dans votre code (probablement dans l’énumération des voisins).

Le pont : c’est l’exercice de convergence entre les deux approches — le même énoncé \(s(f) \le \sqrt{n}\) est observé (Python) et prouvé (Lean). Lean-12 calcule, Lean-12b prouve. Lean-14 (Finiteness) étend à des dérivées booléennes, Lean-16 (Conway Free Will) à un autre théorème emblématique. C’est la leçon pédagogique centrale de la série Lean : empirique + formel = connaissance pleine.

Conclusion

Ce companion natif exhibe la preuve formelle sans-sorry de Huang 2019 dans le kernel Lean lui-même : #check et #print axioms rendent les signatures et les axiomes réels produits par le compilateur, sans intermédiaire Python. La sensitivity conjecture est résolue formellement.

Position dans l’arc pédagogique : Lean-12b est la deuxième moitié de la couverture de Huang 2019. Lean-12 montre le calcul empirique, Lean-12b montre la preuve compilée. La paire illustre un point plus large : un notebook ne devrait pas se contenter de décrire un théorème — il devrait aussi l’ incarner dans le moteur.

Enseignements : 1. #check et #print axioms sont les outils de certification. Sans eux, on est réduit à un acte de foi sur les preuves. Avec eux, on a une garantie syntaxique ET une garantie de complétude (sans sorry). 2. L’architecture stratifiée (vocabulaire → lemme → théorème → portée) est universelle en Lean 4. Lean-12 (Sensitivity), Lean-12b (Sensitivity formelle), Lean-14 (Finiteness), Lean-16 (Conway Free Will) la reproduisent. 3. Le #print axioms est sans complaisance : aucune preuve n’échappe à son audit récursif. Si un sorryAx apparaît, le théorème est incomplet.

Suite : Lean-13 (Kochen-Specker) traite un autre théorème emblématique, Lean-14 (Finiteness Derivatives) étend aux dérivées booléennes, Lean-16 (Conway Free Will) au théorème du libre arbitre de Conway-Kochen. Tous démontrent la même leçon : un théorème prouvé dans le noyau est plus solide qu’un théorème décrit en prose.

Le pont : Lean-12b est un companion formel — son rôle est d’ancrer Lean-12 (empirique). Lean-14 (Finiteness) est lui-même un companion de la théorie des dérivées booléennes. Lean-16 (Conway Free Will) est un companion du théorème Conway-Kochen original. La structure “empirique Python + formel Lean” est la signature de la série Lean-12 / Lean-12b / Lean-14 / Lean-16.

Retour au sommet