GameTheory-18b : Casser la composition — où la meilleure réponse composée cesse d’être l’équilibre du jeu composé

GT-18 a posé la composition d’open games et vérifié la propriété de Hedges — « la meilleure réponse de la composition est la composition des meilleures réponses » — sur un jouet où elle tient, puis mesuré la convergence de la boucle vers son point fixe. Ce notebook fait ce que le critère de maturation demande : il essaie de casser le jouet, et regarde ce qui casse.

Deux surfaces d’attaque :

Références : Hedges (2015), The composition of games ; GT-18 (GameTheory-18-Open-Games-et-Lentilles-Python.ipynb, issue #12212) ; issue #13185 sous l’Epic de maturation #12208.

Objectifs d’apprentissage

  1. Reproduire le régime où la composition tient : couplée mais univoque, la meilleure réponse composée est bien l’équilibre du composé.
  2. Exhiber la casse : ajouter UN ingrédient — la multivocité du plateau — et montrer par déviation explicite qu’un profil issu de la composition n’est pas Nash du composé.
  3. Isoler les ingrédients : le couplage seul ne casse rien (cellule 3), la multivocité seule non plus (r = 0) ; c’est leur conjonction qui brise la sélection.
  4. Mesurer la frontière de contraction : carte convergence / 2-cycle / oscillation sur le pas d’update, comparée à la borne théorique de Banach L = |1 - delt| < 1.
  5. Reconsidérer honnêtement le jouet GT-18 : sa boucle additive n’est jamais contractante (L = 1 partout) — sa convergence est une convergence-au-rail, pas un point fixe de Banach.

1. Le régime où la composition tient — couplée mais univoque

Rappel du cadre GT-18 : deux open games composés en série. Le joueur 1 choisit x, le joueur 2 observe x et choisit y. Le paiement de J2 dépend de x (couplage), celui de J1 de y (couplage en retour). Ici chaque meilleure réponse est univoque : u1 = -(x-1)^2 a un unique maximum en x = 1, et u2 = -(y-x)^2 a un unique maximum en y = x. La composition des argmax donne le profil (1, 1), et ce profil est bien l’équilibre du jeu composé — vérifié par énumération des déviations, pas par affirmation.

import numpy as np

# === Deux open games en serie, COUPLES mais UNIVOQUES ===
ACTIONS_X = (0, 1, 2)
ACTIONS_Y = (0, 1, 2)

def u1(x, y):
    """Paiement J1 : maximum unique en x=1 (le couplage en y est neutre ici)."""
    return -(x - 1.0) ** 2 + 0.0 * y

def u2(x, y):
    """Paiement J2 : couplée, maximum unique en y=x."""
    return -(y - x) ** 2

def br1(y):
    """Meilleure reponse LOCALE de J1 (y exogene) : univoque."""
    return max(ACTIONS_X, key=lambda x: u1(x, y))

def br2(x):
    """Meilleure reponse de J2 voyant x : univoque."""
    return max(ACTIONS_Y, key=lambda y: u2(x, y))

# Composition des selections : x* = br1(y exogene), puis y* = br2(x*)
x_star, y_star = br1(0), None
y_star = br2(x_star)
profil_compose = (x_star, y_star)

# Equilibre du compose : enumeration exhaustive des deviations
def est_nash_compose(x, y):
    """Nash du jeu compose : aucune deviation profitable, J1 anticipant y'=br2(x')."""
    ok1 = all(u1(x, y) >= u1(xp, br2(xp)) - 1e-12 for xp in ACTIONS_X)
    ok2 = all(u2(x, y) >= u2(x, yp) - 1e-12 for yp in ACTIONS_Y)
    return ok1 and ok2

print(f"BR locales univoques : br1(0) = {br1(0)}, br2({x_star}) = {y_star}")
print(f"Profil issu de la composition : {profil_compose}")
print(f"Ce profil est-il Nash du compose : {est_nash_compose(*profil_compose)}")
print("Regime univoque-couple : la composition des selections Donne l'equilibre du compose.")
BR locales univoques : br1(0) = 1, br2(1) = 1
Profil issu de la composition : (1, 1)
Ce profil est-il Nash du compose : True
Regime univoque-couple : la composition des selections Donne l'equilibre du compose.

Lecture de la sortie committée : la composition des argmax produit (1, 1), et l’énumération exhaustive des déviations confirme que c’est l’équilibre du composé. Remarquer ce qui est déjà là : les paiements sont couplés dans les deux sens (u2 dépend de x), et pourtant la composition tient. Le couplage seul ne casse pas la sélection — c’est un contre-fait utile : il faut autre chose. C’est cet « autre chose » que la section 2 installe.

2. Surface A — la multivocité du plateau brise la sélection

On déplace le maximum de J1 au centre exact d’un plateau : u1 = -(x - 0.5)^2 + r * y avec r = 0.3. Sur x ∈ {0, 1, 2}, les valeurs locales sont -0.25, -0.25, -2.25 — x = 0 et x = 1 sont ex æquo : la meilleure réponse locale est multivoque (BR = {0, 1}, plateau par symétrie exacte). La multivocité seule serait inoffensive : avec r = 0, J1 resterait indifférent entre les deux profils composés. Mais le couplage r * y fait que le choix de J1, via la réponse y = x de J2, revient à J1 : deviner x = 1 rapporte r de plus que x = 0. La composition naïve — prendre UN élément du plateau, disons le plus petit — rend un profil que le jeu composé réfute.

# === Surface A : plateau multivoque + couplage ===
C_PLATEAU, R_COUPLAGE = 0.5, 0.3

def u1_A(x, y):
    """Plateau exact : x=0 et x=1 ex aequo en local (c=0.5 = milieu exact)."""
    return -(x - C_PLATEAU) ** 2 + R_COUPLAGE * y

def br1_A_ensemble():
    """CORRESPONDANCE locale de J1 (y exogene = 0) : l'ENSEMBLE des optima."""
    vals = [u1_A(x, 0.0) for x in ACTIONS_X]
    vmax = max(vals)
    return [x for x in ACTIONS_X if abs(u1_A(x, 0.0) - vmax) < 1e-12], vals

br1_A, vals_locales = br1_A_ensemble()
print(f"Valeurs locales de u1 (y exogene) : {[f'{v:+.3f}' for v in vals_locales]}")
print(f"BR locale de J1 = {br1_A}  (MULTIVOQUE : plateau par symetrie exacte c=0.5)")

# Composition des selections : on prend UN element du plateau (le plus petit)
selection = min(br1_A)
profils_composes = [(x, br2(x)) for x in br1_A]
print(f"Profil de la composition naive (plus petit argmax) : ({selection}, {br2(selection)})")
print(f"Ensemble prevu par la composition des correspondances : {profils_composes}")
Valeurs locales de u1 (y exogene) : ['-0.250', '-0.250', '-2.250']
BR locale de J1 = [0, 1]  (MULTIVOQUE : plateau par symetrie exacte c=0.5)
Profil de la composition naive (plus petit argmax) : (0, 0)
Ensemble prevu par la composition des correspondances : [(0, 0), (1, 1)]

Lecture de la sortie committée : la correspondance locale de J1 est {0, 1} — le plateau est exact, produit de la symétrie c = 0.5 au milieu de deux actions consécutives. La composition des correspondances prévoit l’ensemble {(0,0), (1,1)}. Reste à demander au jeu composé ce qu’il en pense : chaque profil prédit est confronté à toutes les déviations, J1 anticipant la réponse de J2.

# === Test Nash du compose, profil par profil ===
def ecart_deviation_J1(x, y):
    """Ecart de paiement si J1 devie vers x' en anticipant y' = br2(x')."""
    if y != br2(x):
        return None   # le profil ne respecte meme pas la BR de J2
    return max(u1_A(xp, br2(xp)) for xp in ACTIONS_X) - u1_A(x, y)

print(f"{'Profil prevu':<14} {'u1(x, y)':>9} {'meilleure deviation J1':>23} {'ecart':>8}  Verdict")
print("-" * 78)
for (x, y) in profils_composes:
    ecart = ecart_deviation_J1(x, y)
    x_best = max(ACTIONS_X, key=lambda xp: u1_A(xp, br2(xp)))
    verdict = "NON-NASH du compose (J1 devie)" if (ecart is not None and ecart > 1e-9) else "equilibre du compose"
    print(f"({x}, {y}){'':<7} {u1_A(x, y):9.3f} ({x_best}, {br2(x_best)}){'':<12} "
          f"{ecart:+8.3f}  {verdict}")

# Contre-fait : R_COUPLAGE = 0 -> le plateau ne casse plus rien
u1_r0 = lambda x, y: -(x - C_PLATEAU) ** 2
ecarts_r0 = [max(u1_r0(xp, br2(xp)) for xp in ACTIONS_X) - u1_r0(x, br2(x)) for (x, y) in profils_composes]
print()
print(f"Contre-fait r=0 (plateau sans couplage) : ecarts = [{ecarts_r0[0]:+.3f}, {ecarts_r0[1]:+.3f}]"
      f" -> les deux profils survivent (indifference, equilibres faibles)")
Profil prevu    u1(x, y)  meilleure deviation J1    ecart  Verdict
------------------------------------------------------------------------------
(0, 0)           -0.250 (1, 1)               +0.300  NON-NASH du compose (J1 devie)
(1, 1)            0.050 (1, 1)               +0.000  equilibre du compose

Contre-fait r=0 (plateau sans couplage) : ecarts = [+0.000, +0.000] -> les deux profils survivent (indifference, equilibres faibles)

Lecture de la sortie committée : la casse est exhibée par déviation explicite. Le profil (0, 0) — prédit par la composition naïve (sélection du plus petit argmax du plateau) — n’est pas Nash du composé : J1, en anticipant que J2 répondra y = x, gagne +0.300 à dévier vers x = 1. Seul (1, 1) survit. Et le contre-fait r = 0 confirme l’isolation des ingrédients : sans couplage, le plateau est inoffensif (les deux profils sont des équilibres faibles par indifférence).

Ce que Hedges garantise vraiment. La propriété de composition, dans sa forme exacte, porte sur les correspondances — les ensembles de meilleures réponses — munies de leur contexte : la composée des correspondances calcule bien l’ensemble des solutions du jeu composé, à contexte correctement propagé. Ce qui ne tient pas, et que le jouet univoque de GT-18 ne pouvait pas montrer, est la lecture fonctionnelle : composer des sélections d’argmax locaux, chacune calculée sans regarder le couplage en retour, ne prédit pas l’équilibre — la composition prédit l’ensemble (sur-approximation), pas le point. Chaque ingrédient est inoffensif seul — couplage sans plateau (section 1), plateau sans couplage (contre-fait r = 0) — c’est leur conjonction qui brise la sélection.

3. Surface B — la frontière de contraction de la boucle

La section 3 de GT-18 itère une boucle W -> P -> decision -> update -> W' et mesure la distance au point fixe. La famille d’update la plus simple qui généralise la sienne est le rappel homing : a' = clip(a + delt * (b - a), -1, 1), qui tire a vers la cible b avec un pas delt. Cette application est affine de pente 1 - delt (donc de constante de Lipschitz L = |1 - delt|) tant que le clip ne mord pas : le théorème du point fixe de Banach garantit contraction, donc convergence géométrique vers b, si et seulement si L < 1, c’est-à-dire delt ∈ (0, 2). À delt = 2 exactement, L = 1 : la boucle rebondit de part et d’autre de la cible sans amortir — un 2-cycle exact. Au-delà, chaque pas amplifie l’écart (a - b -> (1-delt)(a - b) avec |1-delt| > 1) jusqu’à atteindre le rail |a| = 1, où le clip borne la divergence en un cycle de période 2 collé au rail — bornée, la boucle ne converge pas pour autant.

La prédiction théorique est nette : la frontière entre convergence et non-convergence est exactement delt = 2. On la mesure.

# === Surface B : carte delt -> comportement de la boucle ===
B_CIBLE = 0.3

def boucle_homing(a0, delt, b=B_CIBLE, n=120):
    """itere a' = clip(a + delt*(b-a)) et rend la trajectoire."""
    traj = [a0]
    a = a0
    for _ in range(n):
        a = np.clip(a + delt * (b - a), -1.0, 1.0)
        traj.append(a)
    return np.array(traj)

def classifie(traj, b=B_CIBLE, tol=1e-6):
    """converge / 2-cycle interieur / 2-cycle sur rail, depuis la queue."""
    queue = traj[-20:]
    if np.all(np.abs(queue - b) < 1e-4):
        return "converge"
    ecarts = queue - b
    if np.allclose(ecarts[::2], ecarts[0], atol=tol) and np.allclose(ecarts[1::2], ecarts[1], atol=tol):
        sur_rail = np.any(np.abs(np.abs(queue) - 1.0) < 1e-9)
        return "2-cycle sur rail" if sur_rail else "2-cycle interieur"
    return "non stabilise"

DELTAS = [0.5, 1.0, 1.5, 1.9, 2.0, 2.1, 2.5, 3.0]
print(f"{'delt':>5} {'L=|1-delt|':>10} {'a_120':>9} {'|a_120-b|':>10}  comportement")
print("-" * 58)
for delt in DELTAS:
    traj = boucle_homing(0.9, delt)
    comp = classifie(traj)
    print(f"{delt:5.1f} {abs(1-delt):10.2f} {traj[-1]:9.4f} {abs(traj[-1]-B_CIBLE):10.4f}  {comp}")

print()
print("Borne de Banach : contraction ssi L < 1 ssi delt dans (0, 2)")
print("Frontiere mesuree : convergence pour delt <= 1.9, bascule a delt = 2.0 exactement.")
 delt L=|1-delt|     a_120  |a_120-b|  comportement
----------------------------------------------------------
  0.5       0.50    0.3000     0.0000  converge
  1.0       0.00    0.3000     0.0000  converge
  1.5       0.50    0.3000     0.0000  converge
  1.9       0.90    0.3000     0.0000  converge
  2.0       1.00    0.9000     0.6000  2-cycle interieur
  2.1       1.10    1.0000     0.7000  2-cycle sur rail
  2.5       1.50    1.0000     0.7000  2-cycle sur rail
  3.0       2.00    1.0000     0.7000  2-cycle sur rail

Borne de Banach : contraction ssi L < 1 ssi delt dans (0, 2)
Frontiere mesuree : convergence pour delt <= 1.9, bascule a delt = 2.0 exactement.

Lecture de la sortie committée : la frontière mesurée coïncide avec la borne théorique exactement. En dessous de delt = 2 (L < 1), la boucle converge vers la cible b = 0.3 — géométriquement vite près de delt = 1 (L = 0, convergence en un pas), plus lentement aux bords. À delt = 2.0 (L = 1, cas limite non contractant), la boucle rebondit : l’écart change de signe à chaque pas sans changer de magnitude — le 2-cycle exact prédit par l’analyse. Au-delà (L > 1), l’écart s’amplifie à chaque pas jusqu’à mordre le rail |a| = 1 ; le clip a alors remplacé la divergence par un 2-cycle sur rail — une des deux valeurs du cycle est collée au mur — la boucle bornée n’est plus pour autant convergente. Le clip ne répare pas la perte de contraction : il en masque la conséquence visible.

4. Le régime exact de la boucle GT-18 — jamais contractante

Reconsidérons la boucle effectivement committée dans GT-18 : a' = clip(a + delta, -1, 1) — un pas additif constant. Sa pente est 1 partout où le clip ne mord pas : constante de Lipschitz L = 1, le cas limite non contractant, pour toute valeur de delta. Banach ne s’applique pas ; ce qui fait converger la boucle de GT-18 vers 1.0 (cas delta = 0.5) est uniquement le rail : chaque pas ajoute delta, le clip tronque à 1, et la valeur s’y colle — c’est une convergence-au-rail en temps borné (au plus 2/delta pas), pas une convergence géométrique vers un point fixe intérieur. La distinction n’est pas cosmétique : la convergence-au-rail exige un mur pour s’arrêter, la convergence de Banach non — la surface B vient de le mesurer (delt > 2 : même avec un rail, pas d’arrêt).

# === GT-18 reframed : la boucle additive est le cas L=1 partout ===
def boucle_additive(a0, delta, n=120):
    """Boucle GT-18 exacte : a' = clip(a + delta)."""
    traj = [a0]
    a = a0
    for _ in range(n):
        a = np.clip(a + delta, -1.0, 1.0)
        traj.append(a)
    return np.array(traj)

print("Boucle additive GT-18 (L=1 partout, jamais contractante) :")
for delta in (0.5, -0.3):
    traj = boucle_additive(0.5, delta)
    n_rail = next((i for i, a in enumerate(traj) if abs(a - (1.0 if delta > 0 else -1.0)) < 1e-12), None)
    print(f"  delta={delta:+.1f} : atteint le rail en {n_rail} pas, y reste (a_120 = {traj[-1]:+.1f})")
print()
print("Boucle homing contractante (delt=0.8, L=0.2) : convergence GEOMETRIQUE interieure")
traj = boucle_homing(0.9, 0.8)
errs = np.abs(traj[:8] - B_CIBLE)
print(f"  |a_n - b| pour n=0..7 : {[f'{e:.4f}' for e in errs]}")
print(f"  ratio moyen d'amortissement par pas : {(errs[-1]/errs[0])**(1/7):.3f} (theorie L = 0.2)")
print()
print("Convergence-au-rail : temps borne par le mur, arret PAR le mur.")
print("Convergence de Banach : taux geometrique |1-delt|, arret par amortissement interne.")
Boucle additive GT-18 (L=1 partout, jamais contractante) :
  delta=+0.5 : atteint le rail en 1 pas, y reste (a_120 = +1.0)
  delta=-0.3 : atteint le rail en 5 pas, y reste (a_120 = -1.0)

Boucle homing contractante (delt=0.8, L=0.2) : convergence GEOMETRIQUE interieure
  |a_n - b| pour n=0..7 : ['0.6000', '0.1200', '0.0240', '0.0048', '0.0010', '0.0002', '0.0000', '0.0000']
  ratio moyen d'amortissement par pas : 0.200 (theorie L = 0.2)

Convergence-au-rail : temps borne par le mur, arret PAR le mur.
Convergence de Banach : taux geometrique |1-delt|, arret par amortissement interne.

Lecture de la sortie committée : les deux dynamiques sont distinguées par leur signature. La boucle additive de GT-18 atteint le rail en un nombre entier de pas (2/delta ici : 1 pas pour delta = 0.5 partant de 0.5) et s’y colle — l’arrêt est un événement discret, causé par le mur. La boucle homing contractante, elle, amortit son erreur d’un facteur L à chaque pas — mesuré ≈ 0.2, théorie 0.2 — et l’arrêt est interieur, asymptotique, sans mur. Le jouet GT-18 vivait donc dans le cas dégénéré L = 1 : sa « convergence vers le point fixe » était la sédimentation sur le rail, et la section 3 de GT-18 mesurait la distance à un « point fixe » qui n’en était un que par clip.

5. Verdict par surface — ce qui cède, ce qui tient

Surface Ce qui cède Ce qui tient Condition exacte
A — sélection compositionnelle composer des sélections d’argmax locaux sous plateau multivoque + couplage : le profil (0,0) prédit n’est pas Nash (écart +0.300) la propriété de Hedges au sens des correspondances (l’ensemble composé sur-approxime les équilibres : (1,1) y est) ; la composition des sélections en régime univoque (section 1) la casse exige la conjonction plateau × couplage — chacun seul est inoffensif (section 1, contre-fait r = 0)
B — convergence de la boucle la lecture « la boucle converge donc elle est saine » : à L ≥ 1 elle ne converge pas (2-cycle intérieur à delt = 2, 2-cycle sur rail au-delà) ; la boucle GT-18 est L = 1 partout — jamais contractante la frontière de contraction est exactement la borne de Banach delt = 2 — le théorique et le mesuré coïncident sans zone grise convergence géométrique ssi delt ∈ (0, 2) ; convergence-au-rail de GT-18 = arrêt par le mur, pas par amortissement

Le bilan de maturation est positif au sens strict : le jouet GT-18 survit borné — aucun de ses résultats numériques n’était faux — mais son périmètre de validité est désormais écrit : la composition des sélections exige l’univocité (ou l’absence de couplage), et la convergence de sa boucle est de type rail, pas de type Banach. C’est ce que « survivre à une variante -b » veut dire : pas rester intact, avoir ses bornes.

Questions ouvertes — ce que cette variante ne tranche pas

  • La sélection d’équilibre en amont. La surface A montre que la composition sur-approxime l’ensemble des équilibres ; elle ne dit pas lequel un processus décentralisé sélectionne — ni si un raffinement (élimination des équilibres faibles par indifférence) suffirait à rétablir une composition des sélections strictes.
  • Le plateau exact est une symétrie. La multivocité exhibée naît de c = 0.5, milieu exact de deux actions — un plateau de mesure nulle dans l’espace des paramètres. Un plateau épais (plateau d’utilité plate sur un intervalle, fréquent en jeux discrets de coordination) casserait de la même façon, mais la frontière « plateau de mesure nulle vs épais » n’est pas explorée ici.
  • Le clip lisse-t-il jamais ? Sur la surface B, le clip a borné la divergence en oscillation. Il existe des update non lisses où le clip produit au contraire des points fixes attractifs sur le rail (convergence vers le mur avec approche unilatérale) — la taxonomy complète des régimes L > 1 bornés n’est pas dressée.

Exercice 1 : le seuil de couplage

La casse de la surface A exige r > 0 — mais à quel seuil exactement ? Le profil (0, 0) prédit par la composition naïve cesse d’être un équilibre dès que r est strictement positif. Vérifiez-le : balayez r sur np.linspace(0, 0.6, 7) et, pour chaque valeur, recalculez l’écart de déviation de J1 au profil (0, 0). Confirmez que l’écart vaut exactement r (pourquoi ?) et dites ce que devient le verdict à r = 0.

# Exercice 1 a completer
# 1. Pour r dans np.linspace(0.0, 0.6, 7) : reconstruire u1_A avec ce couplage
# 2. Calculer l'ecart de deviation de J1 au profil (0, 0) : max_x u1(x, br2(x)) - u1(0, 0)
# 3. Verifier que l'ecart == r exactement, et expliquer pourquoi (indice : u1(1,1) - u1(0,0) = ... )
# Indice : -(1-0.5)^2 + r*1 - (-(0-0.5)^2 + r*0) = 0 + r = r
print("Exercice a completer")
resultat_ex1 = None  # TODO etudiant : ecarts_par_r = ...
Exercice a completer

Exercice 2 : le 2-cycle en main

À delt = 2.0 exactement, la théorie prédit que l’écart a - b change de signe à chaque pas sans changer de magnitude : a_{n+1} - b = -(a_n - b). Partant de a0 = 0.9 avec b = 0.3 : calculez à la main les quatre premiers termes de la suite des écarts, puis vérifiez avec boucle_homing que la trajectoire exacte les reproduit. Combien vaut l’amplitude du cycle, et pourquoi ne décroît-elle jamais ?

# Exercice 2 a completer
# 1. Main : a0 = 0.9, b = 0.3, delt = 2.0 -> ecarts a_n - b pour n = 0..3
# 2. Verifier avec boucle_homing(0.9, 2.0) : les 4 premiers ecarts
# 3. Amplitude du cycle = |a0 - b| * (1 - 0) = |a0 - b| : pourquoi constante ?
# Indice : a' - b = clip(a + 2(b-a)) - b = (a + 2b - 2a) - b = -(a - b) tant que le clip ne mord pas
print("Exercice a completer")
resultat_ex2 = None  # TODO etudiant : ecarts_theoriques = ...
Exercice a completer

Exercice 3 : la cible hors du domaine

Toute la surface B vise b = 0.3, intérieur au domaine [-1, 1] du clip. Que se passe-t-il quand la cible est hors du domaine — b = 1.5 ? Prédisez d’abord (par écrit) : la boucle a' = clip(a + delt*(b-a)) avec delt = 0.8 converge-t-elle, et vers quoi ? Vérifiez numériquement : la limite est-elle le point fixe de Banach, ou autre chose ? Mesurez la distance finale et interprétez : le clip projette le point fixe sur le domaine fermé.

# Exercice 3 a completer
# 1. Prediction ecrite AVANT simulation : convergence vers b=1.5 ? vers 1.0 ? autre ?
# 2. Simuler boucle_homing(0.9, 0.8, b=1.5, n=120) et mesurer la limite
# 3. Distance finale : |limite - 1.5| = 0.5 -> le point fixe atteignable est projete sur le bord
# Indice : si a < 1 alors a' = a + 0.8*(1.5-a) > a (stritement) et clip(a') = 1 des que a >= 1
print("Exercice a completer")
resultat_ex3 = None  # TODO etudiant : limite_b15 = ...
Exercice a completer

Conclusion et perspectives

GT-18 a survécu à sa variante -b au sens de la maturation : ses résultats tiennent, et leurs bornes sont écrites. Trois acquis :

  1. La sélection n’est pas compositionnelle — la composition de sélections d’argmax locaux rend un profil non-Nash ((0, 0), écart +0.300) dès qu’un plateau multivoque rencontre un couplage ; la propriété de Hedges n’a jamais promis autre chose que la composition des correspondances, qui sur-approxime l’ensemble des équilibres. Prédire le point exige l’univocité — ou une théorie de la sélection.
  2. La frontière de contraction est la borne de Banach, exactement — mesurée à delt = 2 sans zone grise ; au-delà, le clip borne la divergence en oscillation sur rail, il ne la répare pas.
  3. La boucle GT-18 est le cas dégénéré L = 1 — sa convergence est une convergence-au-rail (arrêt par le mur, temps borné), pas une convergence géométrique de Banach (arrêt par amortissement interne). Les deux signatures sont mesurées et distinguées.

Perspectives : le même patron s’applique à chaque objet mathématique porté par un jouet — vérifier la propriété sur le régime où elle tient (GT-18 l’a fait), puis chercher la frontière où elle cesse (ce notebook), puis écrire les bornes dans la prose (fait au §5). Le voisinage immédiat : la sélection d’équilibre dans les jeux composés à contextes multiples, et la taxonomy complète des boucles bornées non contractantes.

Retour au sommet