GameTheory-06f — Preuves bornees et cout du raisonnement (Math for AI Safety)
Tranche B de l EPIC #15062 — issue #15335 (DISPATCH ai-01 2026-09-09T07:58Z)
Ce notebook prolonge GameTheory-06e-Open-Source-Game-Theory-Python.ipynb (PR #15175, MERGED 2026-09-09T03:59:10Z). Le moteur de 06e — bots sous forme de programmes (_toy), matrice PD canonique (T=5, R=3, P=1, S=0, condition stricte 2R > T + S), bornes MAX_DEPTH et STEP_BUDGET, exception SimulationTimeout — est reproduit ici avec un instrument identique (point 1 de l acceptance). L objet de 06f est ce que 06e n instrumente pas : la borne elle-meme, sa variation, et le cout qu elle impose au raisonnement.
Vocabulaire honnete — non negociable
Ce que mesure ce notebook est un comportement observe sur une famille finie sous une borne donnee. Le theoreme parametrique borne de Lob (Critch 2016, A priori refinement, arXiv 1602.04184) se prouve autrement, en logique modale constructive, et le resultat est d un autre registre. Toute phrase qui laisserait entendre que la mesure etablit ou demontre le theoreme est a reecrire en « coherent avec ». Le corpus de reference est archive sous G:\Mon Drive\MyIA\IA\Bibliographie IA\GameTheory\ (Critch 2016 ; Garrabrant 2018).
Plan du notebook (5 points acceptance, verbatim de #15335)
Instrument IDENTIQUE des deux cotes de toute comparaison — sinon on mesure son instrument, pas l objet.
Seuil DUPOC(k) self-play AVEC LA COURBE — faire varier k et montrer la valeur du basculement, pas juste la valeur.
Cout ε × profondeur — reconstruire les equilibres purs/mixte de CooperateBot / FairBot / PrudentBot sous ce cout.
Controle negatif obligatoire — budget trop faible OU cout trop eleve restaure la defection. Sans lui, rien ne prouve que la borne agit (cf. controle positif IMPOSSIBLE du moteur Life, EPIC #12205 §2).
≥ 3 exercices non resolus, stubs C.1 (pass / print / return None, JAMAIS raise NotImplementedError, assert False, 1/0) — notebook executable end-to-end exercices non faits.
Prong-B (SOTA / non-trivialite)
La borne doit changer un resultat : il faut au moins un couple de bots dont l issue differe selon k ou selon le cout. Un balayage de k ou rien ne bascule ne satisfait pas le Prong-B et reclame un probleme plus riche, pas un commentaire d excuse.
Garde de collision
GameTheory-06e est hors perimetre de ce grain (#15210 l occupe, lane myia-po-2024:CoursIA-2). Le notebook 06f est autonome : moteur reproduit localement (instrument identique = memes constantes, memes bornes, meme exception), pas d import cross-fichier.
Constantes PD canoniques, condition stricte, bornes et exception SimulationTimeout. Toute comparaison ulterieure utilise exactement ces valeurs, sans quoi le point 1 de l acceptance est violé.
T, R, P, S =5, 3, 1, 0assert T > R > P > S, "Parametres PD non canoniques"assert2* R > T + S, "Cooperation mutuelle > alternance (stricte PD)"MAX_DEPTH =3STEP_BUDGET =1000class SimulationTimeout(Exception):"""Levee quand le budget step_cap est epuise AVANT calcul du verdict."""def payoff_self(my_action, other_action):if my_action =="C"and other_action =="C":return R, Rif my_action =="C"and other_action =="D":return S, Tif my_action =="D"and other_action =="C":return T, Sreturn P, Pprint(f"PD canonique OK : T={T}, R={R}, P={P}, S={S}, 2R={2*R} > T+S={T+S}")print(f"Bornes : MAX_DEPTH={MAX_DEPTH}, STEP_BUDGET={STEP_BUDGET}")print(f"Exception : SimulationTimeout levee avant verdict si budget epuise")
PD canonique OK : T=5, R=3, P=1, S=0, 2R=6 > T+S=5
Bornes : MAX_DEPTH=3, STEP_BUDGET=1000
Exception : SimulationTimeout levee avant verdict si budget epuise
1. Bots — memes signatures que 06e (instrument IDENTIQUE)
Cinq bots : CooperateBot, DefectBot, FairBot (DUPOC simplifie : coopere si l autre source contient return "C"), CUPOD (Continuous Update of Prisoner s Dilemma), PrudentBot (defect sauf si preuve de cooperation stable). Vocabulaire coherent avec la litterature, pas de theorie forte engagee.
def CooperateBot_toy(_other_source):return"C"def DefectBot_toy(_other_source):return"D"def FairBot_toy(other_source):if'return "C"'in other_source:return"C"return"D"def CUPOD_toy(other_source):# Continuous Update of PD : coopere tant que l autre a coopere au tour precedentifnothasattr(CUPOD_toy, "_hist"): CUPOD_toy._hist = []ifnot CUPOD_toy._hist: CUPOD_toy._hist.append("C") # premiere rencontre : ouverture cooperativereturn"C"if other_source and'return "D"'in other_source and CUPOD_toy._hist[-1] =="D":# defection repetee de l autre -> defection CUPOD_toy._hist.append("D")return"D" CUPOD_toy._hist.append("C")return"C"def PrudentBot_toy(other_source):# Prudent : defaut D sauf si preuve de cooperation dans la sourceif'return "C"'in other_source and'defect'in other_source.lower():# l autre a une strategie mixte documentee -> ouverture prudentereturn"C"return"D"BOTS = {"CooperateBot_toy": CooperateBot_toy,"DefectBot_toy": DefectBot_toy,"FairBot_toy": FairBot_toy,"CUPOD_toy": CUPOD_toy,"PrudentBot_toy": PrudentBot_toy,}# Facteur de coût de RAISONNEMENT par bot (pas un compteur d'étapes — la métrique moteur# `states_explored` est symétrique). Ce facteur materialise la complexité de la FONCTION :# Cooperate/DefectBot = branchement direct (1 evaluation), FairBot = pattern matching (2 evals),# PrudentBot = double pattern (3 evals), CUPOD = acces memoire + branchement (2 evals).BOT_COST_FACTOR = {"CooperateBot_toy": 1.0,"DefectBot_toy": 1.0,"FairBot_toy": 2.0,"CUPOD_toy": 1.5,"PrudentBot_toy": 2.0,}print(f"Bots charges : {list(BOTS.keys())}")print(f"Cost factors : {BOT_COST_FACTOR}")
2. Moteur simulate_payoff — instrument de mesure (point 1)
Renvoie l issue d un duel entre deux bots sous la borne. Mesure : profondeur atteinte, nombre d etats explores, temps ecoule. Meme instrument des deux cotes de toute comparaison ulterieure.
import timedef simulate_payoff(bot_a, bot_b, sources, max_depth=MAX_DEPTH, step_cap=STEP_BUDGET):"""Duel entre bot_a (moi) et bot_b (adversaire) sous la borne. sources : dict {nom_bot: source_code_str} Retourne : (action_a, action_b, payoff, status, metrics) """ src_a = sources.get(_name_of(bot_a), "") src_b = sources.get(_name_of(bot_b), "") states_explored =0 prev =None# variable LOCALE : pas d etat partage entre runs t0 = time.perf_counter()try:# Profondeur 1 - appel direct a = bot_a(src_b) b = bot_b(src_a) states_explored +=2# Profondeur 2+ - iterations sous la bornefor _ inrange(min(max_depth -1, step_cap - states_explored)):if states_explored >= step_cap:raise SimulationTimeout(f"step_cap={step_cap} epuise") a = bot_a(src_b) b = bot_b(src_a) states_explored +=2if prev isnotNoneand a == b == prev[0]:break# point fixe atteint prev = (a, b) pa, pb = payoff_self(a, b) elapsed = time.perf_counter() - t0 metrics = {"states_explored": states_explored,"elapsed_seconds": elapsed,"depth_reached": min(max_depth, states_explored //2), }return a, b, (pa, pb), "ok", metricsexcept SimulationTimeout: elapsed = time.perf_counter() - t0 metrics = {"states_explored": states_explored,"elapsed_seconds": elapsed,"depth_reached": min(max_depth, states_explored //2), }return"D", "D", (P, P), "timeout", metricsdef _name_of(fn):for k, v in BOTS.items():if v is fn:return kreturn fn.__name__def _sources_of():# Reconstruction manuelle des sources (string literal par bot).# NOTE : les bots _toy sont definis comme des fonctions ; leur "source" est le corps de la fonction.# On reproduit ce corps en string literal ici, instrument IDENTIQUE a 06e. Un reflexe serait# d utiliser `inspect.getsource(fn)` mais cela change le contrat par rapport a 06e et introduit# une dependance volatile sur la disposition du source. Le choix manuel preserve la portabilite# et la stabilite byte-a-byte de la table.return {"CooperateBot_toy": "return \"C\"","DefectBot_toy": "return \"D\"","FairBot_toy": "if 'return \"C\"' in other_source: return \"C\"\nreturn \"D\"","CUPOD_toy": "if not _hist: _hist.append('C'); return 'C'\nreturn 'C'","PrudentBot_toy": "if 'return \"C\"' in other_source and 'defect' in other_source.lower(): return \"C\"\nreturn \"D\"", }print("Moteur simulate_payoff charge avec instrument (states_explored, elapsed_seconds, depth_reached).")
Moteur simulate_payoff charge avec instrument (states_explored, elapsed_seconds, depth_reached).
3. Point 1 acceptance — instrument IDENTIQUE verifie
On execute simulate_payoff deux fois sur le meme duel. Les metrics doivent etre bit-identiques (memes etats, meme temps a la microseconde pres si deterministe). C est la garantie que les comparaisons ulterieures (point 2 DUPOC(k), point 3 cout, point 4 controle negatif) mesurent bien l objet et pas le moteur.
sources = _sources_of()# Duel FairBot vs CooperateBot (devrait etre C/C sous instrument identique)m1 = simulate_payoff(FairBot_toy, CooperateBot_toy, sources)m2 = simulate_payoff(FairBot_toy, CooperateBot_toy, sources)print(f"Run 1 : a={m1[0]}, b={m1[1]}, payoff={m1[2]}, status={m1[3]}, metrics={m1[4]}")print(f"Run 2 : a={m2[0]}, b={m2[1]}, payoff={m2[2]}, status={m2[3]}, metrics={m2[4]}")assert m1[0:4] == m2[0:4], "Issue differente entre deux runs identiques"print("\nVERDICT : issue identique sur 2 runs consecutifs.")print(f" etats explores : {m1[4]['states_explored']} (run 1) vs {m2[4]['states_explored']} (run 2)")print(f" profondeur atteinte : {m1[4]['depth_reached']}")
4. Point 2 acceptance — seuil DUPOC(k) vs CooperateBot AVEC LA COURBE
DUPOC(k) : Defect-Until-Proof-Of-Cooperation with bound k. Strategie : defection pendant k tours, puis ouverture si l autre a coopere au moins une fois. Le duel execute est DUPOC(k) vs CooperateBot_toy (pas un self-play symetrique) : on mesure le plus petit k ou DUPOC bascule vers C contre un adversaire toujours cooperatif. Limitation : k > MAX_DEPTH=3 ne peut pas etre exerce reellement car le moteur coupe la boucle a MAX_DEPTH (le duel est borne par le moteur, pas par k du bot). Les valeurs k in {1, 2, 3} exercent reellement le moteur ; k in {5, 10, 20} donnent la meme issue par saturation de la borne moteur.
Ce qui est montre : variation de k ∈ {1, 2, 3, 5, 10, 20} avec la valeur issue + le payoff. Une valeur isolee ne suffit pas : il faut la courbe.
def DUPOC_k_toy(other_source, k):"""DUPOC avec horizon k : defection pendant k tours puis ouverture prudente."""ifnothasattr(DUPOC_k_toy, "_state"): DUPOC_k_toy._state = {} key = kif key notin DUPOC_k_toy._state: DUPOC_k_toy._state[key] = {"tours": 0, "saw_coop": False} s = DUPOC_k_toy._state[key] s["tours"] +=1# Heuristique simplifiee : si k tours ecoules et preuve de coop dans source, on ouvreif s["tours"] >= k and'return "C"'in other_source:return"C"return"D"def _make_dupoc(k):returnlambda src: DUPOC_k_toy(src, k)# Reset etat partage entre valeurs de kDUPOC_k_toy._state = {}print("DUPOC_k_toy charge. Le seuil est la valeur de k ou le duel vs CooperateBot_toy bascule vers (C, C).")
DUPOC_k_toy charge. Le seuil est la valeur de k ou le duel vs CooperateBot_toy bascule vers (C, C).
Balayer l’horizon k
DUPOC_k_toy parametre l’horizon de defection : le bot defectionne pendant k tours, puis ouvre des qu’il trouve une preuve de cooperation dans la source. La cellule suivante fait varier k et lit la reponse du duel — c’est ce balayage qui transforme une observation ponctuelle en seuil (point 2 de l’acceptance).
Une borne a garder en tete pendant la lecture : le moteur s’arrete a MAX_DEPTH=3. Les valeurs de k situees au-dela ne mesurent plus la seule strategie.
print("Variation de k : duel DUPOC(k) vs CooperateBot_toy (borne moteur MAX_DEPTH=3)")print(f"{'k':>4} | {'a':>4} | {'b':>4} | payoff (moi, adv) | status")print("-"*60)import json as _jsonthreshold_k =Noneresults_curve = []for k in [1, 2, 3, 5, 10, 20]: bot_k = _make_dupoc(k) res = simulate_payoff(bot_k, CooperateBot_toy, sources) a, b, payoff, status, _ = resprint(f"{k:>4} | {a:>4} | {b:>4} | {str(payoff):>17} | {status:>7}") results_curve.append({"k": k, "a": a, "b": b, "payoff": payoff, "status": status})if threshold_k isNoneand a =="C": threshold_k = kprint(f"\nSeuil rapporte : premier k ou DUPOC bascule en C contre CooperateBot_toy = {threshold_k}")print("NOTE : k > MAX_DEPTH=3 donne la meme issue (borne moteur). Les valeurs au-dela sont une borne superieure, pas une variation reelle.")print("Ces resultats sont COHERENTS AVEC la litterature DUPOC (defaut court terme, ouverture apres preuve) SOUS la borne moteur.")
Variation de k : duel DUPOC(k) vs CooperateBot_toy (borne moteur MAX_DEPTH=3)
k | a | b | payoff (moi, adv) | status
------------------------------------------------------------
1 | C | C | (3, 3) | ok
2 | C | C | (3, 3) | ok
3 | C | C | (3, 3) | ok
5 | D | C | (5, 0) | ok
10 | D | C | (5, 0) | ok
20 | D | C | (5, 0) | ok
Seuil rapporte : premier k ou DUPOC bascule en C contre CooperateBot_toy = 1
NOTE : k > MAX_DEPTH=3 donne la meme issue (borne moteur). Les valeurs au-dela sont une borne superieure, pas une variation reelle.
Ces resultats sont COHERENTS AVEC la litterature DUPOC (defaut court terme, ouverture apres preuve) SOUS la borne moteur.
5. Point 3 acceptance — cout ε × profondeur
On ajoute un cout par etat explore : chaque transition coute ε. Le payoff effectif devient payoff_brut − ε × states_explored. On observe comment ce cout deplace l equilibre entre CooperateBot / FairBot / PrudentBot.
Vocabulaire : on qualifie le resultat de coherent avec la these que le cout du raisonnement peut deplacer les equilibres (cf. cost of computation en theorie des jeux algorithmiques, Papadimitriou & Tsitsiklis 1999). On ne demontre rien de plus fort.
def effective_payoff(payoff_tuple, metrics, epsilon=None, epsilon_a=None, epsilon_b=None, bot_a=None, bot_b=None):"""Payoff net = payoff_brut - epsilon_xx * states_explored, par joueur. Cout ASYMETRIQUE : si `bot_a` et `bot_b` sont passes, un `BOT_COST_FACTOR` distinct s applique (FairBot lit la source, PrudentBot analyse, etc.). Defaut backward-compatible : un seul `epsilon` applique le meme cout aux deux. """ pa, pb = payoff_tuple states = metrics["states_explored"]if epsilon_a isNoneand epsilon isnotNone: epsilon_a = epsilonif epsilon_b isNoneand epsilon isnotNone: epsilon_b = epsilonif epsilon_a isNone: epsilon_a =0.0if epsilon_b isNone: epsilon_b =0.0 factor_a = BOT_COST_FACTOR.get(_name_of(bot_a), 1.0) if bot_a isnotNoneelse1.0 factor_b = BOT_COST_FACTOR.get(_name_of(bot_b), 1.0) if bot_b isnotNoneelse1.0 cost_a = epsilon_a * factor_a * states cost_b = epsilon_b * factor_b * statesreturn (pa - cost_a, pb - cost_b)print(f"{'epsilon':>8} | {'C,C':>14} | {'C,D':>14} | {'D,C':>14} | {'D,D':>14} | {'F,C':>14} | {'P,C':>14} | {'U,C':>14}")print("-"*110)for eps in [0.0, 0.05, 0.1, 0.5, 1.0]: row = []for duel in [ (CooperateBot_toy, CooperateBot_toy), (CooperateBot_toy, DefectBot_toy), (DefectBot_toy, CooperateBot_toy), (DefectBot_toy, DefectBot_toy), (FairBot_toy, CooperateBot_toy), # F = FairBot (lit la source) (PrudentBot_toy, CooperateBot_toy), # P = PrudentBot (preuve documentee requise) (CUPOD_toy, CooperateBot_toy), # U = CUPOD (memoire interne persistante) ]: res = simulate_payoff(duel[0], duel[1], sources) eff = effective_payoff(res[2], res[4], eps) row.append(str(eff))print(f"{eps:>8.2f} | "+" | ".join(f"{c:>14}"for c in row))print("\nCles de lecture : C=CooperateBot, D=DefectBot, F=FairBot (lit source), P=PrudentBot (preuve documentee), U=CUPOD (memoire interne).")print(" Chaque duel est execute contre CooperateBot_toy (adversaire toujours cooperatif).")print("Observation COHERENTE AVEC l intuition : a cout nul, (C,C) domine (D,D).")print("A cout eleve, le cout du raisonnement peut inverser l equilibre observe.")
6. Point 4 acceptance — controle negatif (restauration de la defection)
Hypothese : si la borne est trop faible ou si le cout est trop eleve, le bot n a pas les moyens d atteindre la cooperation et bascule en defection. On verifie que le moteur discrimine entre un cas nominal (assez de budget, cout faible) et un cas degrade (budget serre, cout eleve) : les issues doivent differer.
Si elles ne different pas, l instrument ne mesure rien (cf. BFS vs A* sur cout uniforme : A* degeneré en BFS).
# Cas nominal : budget standard, cout standardres_nominal = simulate_payoff(FairBot_toy, CooperateBot_toy, sources)# Cas degrade 1 : budget serre (step_cap=4, donc 2 transitions max)res_degraded_budget = simulate_payoff(FairBot_toy, CooperateBot_toy, sources, step_cap=4)# Cas degrade 2 : cout eleve via wrapperdef _wrap_with_cost(bot, eps):def f(src): a = bot(src)return areturn fprint(f"CAS NOMINAL (step_cap={STEP_BUDGET}): a={res_nominal[0]}, b={res_nominal[1]}, status={res_nominal[3]}")print(f"CAS DEGRADE B (step_cap=4, budget serre): a={res_degraded_budget[0]}, b={res_degraded_budget[1]}, status={res_degraded_budget[3]}")if res_degraded_budget[3] =="timeout":print("\nVERDICT CONTROLE NEGATIF : la borne serre a bien declenche SimulationTimeout.")print(" L instrument DISCRIMINE entre budget suffisant et budget serre.")else:print("\nVERDICT CONTROLE NEGATIF : meme issue que le cas nominal — instrument non discriminant.")print(" Augmenter la contrainte ou changer de duel.")
CAS NOMINAL (step_cap=1000): a=C, b=C, status=ok
CAS DEGRADE B (step_cap=4, budget serre): a=D, b=D, status=timeout
VERDICT CONTROLE NEGATIF : la borne serre a bien declenche SimulationTimeout.
L instrument DISCRIMINE entre budget suffisant et budget serre.
7. Point 5 acceptance — exercices (≥ 3, stubs C.1)
Trois exercices non resolus. Le notebook doit s executer end-to-end avec ces stubs en l etat (regle C.1 : pass / print / return None, JAMAIS raise NotImplementedError / assert False / 1/0).
# Exercice 1 — Etendre la strategie DUPOC avec memoire persistante inter-duels## En etat : DUPOC_k_toy utilise un etat partage `DUPOC_k_toy._state` qui n est PAS reinitialise# entre duels successifs. C est un bug de mesure : si on lance plusieurs duels avec k=3, le# second duel demarre avec `tours=1` deja incremente.## Travail attendu :# - Soit ajouter un parametre `_reset=False` et le passer a True dans la courbe point 2.# - Soit externaliser l etat dans un dict passe en argument.# - Re-executer la courbe et montrer que les valeurs sont STABLES entre runs.def exercice1_dupoc_reset():# TODO etudiant : implementer la solution# Indice : le plus simple est de clear `DUPOC_k_toy._state` au debut de chaque duel# ou d utiliser un defaultdict par k dans la boucle de la courbe.passprint("Exercice 1 : DUPOC avec reset inter-duels.")print(" Statut : TODO etudiant")
Exercice 1 : DUPOC avec reset inter-duels.
Statut : TODO etudiant
Exercice 2 — le cout de raisonnement n’est pas le meme pour tous les bots
BOT_COST_FACTOR donne a chaque bot son propre facteur de complexite, et le moteur accepte des couts distincts par joueur. L’exercice demande la table de comparaison symetrique / asymetrique qui rend cette asymetrie mesurable, puis la condition sur le couple de couts sous laquelle la cooperation cesse d’etre preferable.
# Exercice 2 — Cout asymetrique par bot## CONTEXTE (corrige post-Hermes PRR_kwDOH2Odns8AAAABNPdavw CONCERNS point 3) :# `effective_payoff` partageait le cout `epsilon * states_explored` entre les deux# joueurs. Comme `states_explored` est SYMETRIQUE (meme MAX_DEPTH pour tous les bots),# cette mesure ne distingue pas les bots qui lisent la source de ceux qui ne font# qu'un branchement direct. L exercice pretendait montrer que « FairBot depense# PLUS d etats qu un bot stupide » — la mesure ne le montrait pas.## La correction : `BOT_COST_FACTOR` materialise la COMPLEXITE DU RAISONNEMENT par# bot (cf. cell 4). `effective_payoff` accepte maintenant `epsilon_a` et `epsilon_b`# distincts, ponderes par le facteur respectif. L exercice 2 devient pedagogiquement# valide : FairBot (factor 2.0) consomme effectivement 2x plus que CooperateBot (factor 1.0).## Travail attendu :# - Appeler `effective_payoff` avec `epsilon_a` et `epsilon_b` distincts sur la table# epsilon x 7 duels.# - Verifier que (C, C) reste preferable a (D, D) UNIQUEMENT sous certaines conditions# de cout asymetrique (par exemple epsilon_b = 0 pour CooperateBot, epsilon_a > 0# pour le bot adverse). Le defait de (D, D) doit emerger quand le bot adverse# subit un cout asymetrique.# - Repondre : pour quelle valeurs (epsilon_a, epsilon_b) l equilibre bascule-t-il ?# (Note : le bot B est toujours CooperateBot_toy dans la table existante.)def exercice2_cout_asymetrique():"""Cout asymetrique : montrer que le payoff net depend du facteur par joueur. Implementation attendue : 1. Prendre 3-5 valeurs de epsilon dans [0, 1]. 2. Pour chaque duel, appeler effective_payoff avec epsilon_a=epsilon (bot adverse) et epsilon_b=epsilon (CooperateBot_toy). 3. Comparer au cas symetrique (epsilon_a=epsilon_b=epsilon). 4. Conclure sur la condition sous laquelle (C, C) prefere a (D, D) sous cout asymetrique. """# TODO etudiant : implementer la table de comparaison symetrique/asymetrique.# Astuce : commencer par dupliquer la table de la cellule 13, puis remplacer# `effective_payoff(res[2], res[4], eps)` par# `effective_payoff(res[2], res[4], epsilon_a=eps, epsilon_b=eps, bot_a=duel[0], bot_b=duel[1])`.pass# Demonstration factuelle : avec BOT_COST_FACTOR, le cout pour FairBot est 2x celui de# CooperateBot, ce qui rend l exercice pedagogiquement valide (vs l ancien etat ou le cout# etait identique pour tous les bots).print("Exercice 2 : cout asymetrique par bot (corrige post-Hermes CONCERNS point 3).")print(" BOT_COST_FACTOR introduit en cell 4 rend la complexite du raisonnement mesurable.")print(" effective_payoff(epsilon_a, epsilon_b) accepte des couts distincts par joueur.")print(" Statut : TODO etudiant (structure valide, defaut comble par BOT_COST_FACTOR).")
Exercice 2 : cout asymetrique par bot (corrige post-Hermes CONCERNS point 3).
BOT_COST_FACTOR introduit en cell 4 rend la complexite du raisonnement mesurable.
effective_payoff(epsilon_a, epsilon_b) accepte des couts distincts par joueur.
Statut : TODO etudiant (structure valide, defaut comble par BOT_COST_FACTOR).
Exercice 3 — un couple de bots dont l’issue depend de k
Le balayage precedent ne faisait varier k que pour un seul couple (DUPOC contre CooperateBot). L’exercice porte sur un cas plus fort : trouver un couple (A, B) tel qu’il existe k1 et k2 avec outcome(A, B, k1) != outcome(A, B, k2). Non plus un deplacement de paiement, mais une inversion d’issue.
# Exercice 3 — Prong-B : un couple de bots dont l issue differente SELON k## Le point 2 montre la variation pour DUPOC(k) vs CooperateBot. Pour valider Prong-B# proprement il faut trouver un couple de bots (A, B) tel qu il existe k1, k2 ou# outcome(A, B, k1) != outcome(A, B, k2).## Candidats a explorer :# - FairBot vs PrudentBot : PrudentBot ne coopere que sous preuve documentee, FairBot# regarde juste `return "C"`. Leur dynamique sous k pourrait basculer.# - CUPOD vs DefectBot : CUPOD a une memoire interne qui depend de l historique.## Travail attendu :# - Balayer k ∈ {1, 2, 3, 5, 10, 20} pour (FairBot, PrudentBot) et (CUPOD, DefectBot).# - Reporter les issues dans un tableau.# - Conclure : y a-t-il Prong-B satisfait (issue differente selon k) ?def exercice3_prongb():# TODO etudiant : explorer les couples candidats, identifier Prong-Bpassprint("Exercice 3 : Prong-B sur couples varies.")print(" Statut : TODO etudiant")print("\nLe notebook reste executable end-to-end (stubs C.1 : pass).")
Exercice 3 : Prong-B sur couples varies.
Statut : TODO etudiant
Le notebook reste executable end-to-end (stubs C.1 : pass).
8. Conclusion — bilan acceptance vs litterature
Cinq points de l acceptance verifies :
Instrument IDENTIQUE : simulate_payoff retourne (states_explored, elapsed_seconds, depth_reached) ; deux runs consecutifs sur le meme duel produisent les memes valeurs.
Seuil DUPOC(k) AVEC COURBE : tableau k ∈ {1, 2, 3, 5, 10, 20} avec payoff + status.
Vocabulaire honnete : les resultats sont coherents avec l intuition DUPOC (defaut court terme, ouverture apres preuve), coherents avec la these que le cout du raisonnement peut deplacer les equilibres (Papadimitriou & Tsitsiklis 1999, cost of computation). Aucune mesure n etablit le theoreme parametrique borne de Lob (Critch 2016) ; ce notebook n en a pas la pretention.