07 - Élections de comité par approbation : le core existe toujours
Série SocialChoice — notebook 07. Ce notebook distille le résultat de Becker, Greger & Peters, « Existence of the Core in Approval-Based Committee Elections » (arXiv:2609.11912, 10/09/2026) : la principale question ouverte de la théorie des élections multi-vainqueurs — existe-t-il toujours un comité dans le core ? — est résolue par l’affirmative.
Avertissement de fraîcheur. Preprint de quelques jours, sans validation communautaire au jour de rédaction ; le champ Comments du papier indique « The proof was obtained with GPT-6 Astra ». Tout ce qui suit cite donc « la preuve annoncée », jamais « le théorème établi ». La partie vérifiée indépendamment dès aujourd’hui : l’existence d’un comité Hare-core a été vérifiée formellement en Lean dans le projet ABCVotingLean du même Peters — l’encart final y revient.
Ce que ce notebook fait, à échelle de jouet (n ≤ 8 votants, m ≤ 8 candidats) :
définir le core (quotas Hare et Droop) et la hiérarchie JR → EJR → core ;
exhiber le contre-exemple type : un comité bloqué par une coalition ;
implémenter la règle de l’entropie harmonique du papier — \(\mathcal{V}(W) = \max_{(p,r) \in \mathcal{P}(W)} \sum_i F(p_i, r_i)\) — et vérifier empiriquement que son argmax est toujours dans le core ;
comparer avec les règles usuelles (approbation simple, PAV) ;
relier le core électoral au cœur des jeux coopératifs (GT-27 Kuhn-Munkres, Shapley-Shubik).
Prérequis : notebooks 01 (Arrow), 03 (méthodes de vote) — le core généralise à des groupes ce qu’Arrow et Gibbard imposent à des individus.
1. Cadre : profil d’approbation, taille de comité, quota
Une instance d’élection est \(I = (A, k)\) : chaque votant \(i\) approuve un ensemble \(A_i \subseteq C\) de candidats (bulletin non ordonné), et on élit un comité \(W\) de taille \(k\). L’utilité d’approbation est \(u_i(W) = |A_i \cap W|\).
Le quota\(q\) mesure combien de votants « méritent » un élu. Le quota de Hare est \(q = n/k\) (chaque élu représente un n/k-ième de l’électorat) ; le quota de Droop est \(q = n/(k+1)\), plus exigeant.
Nous utilisons tout du long un exemple fil rouge à 4 votants et 4 candidats : deux votants approuvent \(\{a, b\}\), un approuve \(\{c\}\), un approuve \(\{d\}\), et on élit \(k=2\) élus (quota de Hare \(q = 4/2 = 2\)).
import itertoolsimport numpy as npfrom scipy.optimize import minimizerng = np.random.default_rng(42)# Exemple fil rouge : 4 votants, 4 candidats, k = 2, quota Hare q = 2A = [frozenset("ab"), frozenset("ab"), frozenset("c"), frozenset("d")]CANDS =sorted(set().union(*A))N, K =len(A), 2Q_HARE = N / KQ_DROOP = N / (K +1)def u(i, W):returnlen(A[i] &set(W))print(f"Profil : {[sorted(a) for a in A]}")print(f"n={N}, k={K}, quota Hare q={Q_HARE}, quota Droop q={Q_DROOP:.3f}")
Un comité \(W\) est dans le core s’il n’existe pas de coalition bloquante : un groupe \(N'\) de votants et un ensemble \(T\) de candidats tels que
\(|N'| \ge q \cdot |T| > 0\) — le groupe est assez gros pour « mériter » \(T\) ;
chaque membre de \(N'\) obtient strictement plus de \(T\) que de \(W\) : \(|T \cap A_i| \ge u_i(W) + 1\) pour tout \(i \in N'\).
Personne ne peut alors proposer un comité alternatif qu’un groupe suffisamment gros préférerait unanimement. C’est l’extension aux coalitions de l’absence de gagnant de Condorcet battu — et le concept de stabilité le plus exigeant de la famille JR → EJR → FJR → core (chaque maillon demande moins au témoin : JR exige juste un candidat commun approuvé hors \(W\), EJR un ensemble \(T\) complet, le core laisse le groupe choisir librement son \(T\)).
Le vérificateur ci-dessous énumère les paires \((N', T)\) — possible car nous restons à l’échelle de jouet.
def is_core(A, k, W, q=None):"""True ssi W est dans le core (eq. 2 du papier, forme classique). Retourne (ok, temoin) ; le temoin (N', T) explique un blocage.""" n =len(A) q = q if q isnotNoneelse n / k W =frozenset(W) cands =sorted(set().union(*A))for t inrange(1, len(cands) +1):for T in itertools.combinations(cands, t): T =frozenset(T) members = [i for i inrange(n) iflen(T & A[i]) >=len(W & A[i]) +1]if members andlen(members) >= q * t:returnFalse, (members, sorted(T))returnTrue, None# Contre-exemple type : W = {c, d} laisse v1, v2 sans aucun eluok_cd, temoin = is_core(A, K, "cd")ok_ab, _ = is_core(A, K, "ab")print(f"W = {{c, d}} dans le core : {ok_cd}")ifnot ok_cd: Np, T = temoinprint(f" blocage : N' = {[f'v{i+1}'for i in Np]} (|N'| = {len(Np)} >= "f"q*|T| = {Q_HARE}*{len(T)}), T = {T}")for i in Np:print(f" v{i+1} approuve {sorted(A[i])} : u_i(W) = {u(i, 'cd')} "f"< |T inter A_i| = {len(frozenset(T) & A[i])}")print(f"W = {{a, b}} dans le core : {ok_ab}")
W = {c, d} dans le core : False
blocage : N' = ['v1', 'v2'] (|N'| = 2 >= q*|T| = 2.0*1), T = ['a']
v1 approuve ['a', 'b'] : u_i(W) = 0 < |T inter A_i| = 1
v2 approuve ['a', 'b'] : u_i(W) = 0 < |T inter A_i| = 1
W = {a, b} dans le core : True
Lecture. Le comité \(\{c, d\}\) sacrifie les deux premiers votants : la coalition \(\{v_1, v_2\}\), forte de 2 votants (le quota entier pour 1 siège), peur leur proposer \(T = \{a\}\) qu’ils approuvent tous deux et qui les fait passer de 0 à 1 élu. Blocage. À l’inverse \(\{a, b\}\) ne peut être bloqué par aucun groupe : \(v_3\) et \(v_4\) sont trop peu nombreux (1 < 2) pour mériter un siège à eux seuls.
JR et EJR en passant. JR (juste représentation) exige : si un votant n’approuve personne dans \(W\), alors un groupe d’au moins \(q\) votants partageant un candidat approuvé hors \(W\) existe. EJR renforce : un tel groupe de \(q \cdot t\) votants doit avoir un membre avec au moins \(t\) élus approuvés. Le core exige l’inexistence de n’importe quel\(T\) — JR et EJR n’en vérifient que des formes particulières. Sur le fil rouge, \(\{c, d\}\) viole JR (v1, v2 sans représentant) et \(\{a, b\}\) satisfait tout.
3. Paiements et certificat : le théorème 3.3
La preuve annoncée ne travaille pas sur les blocages mais sur des systèmes de paiement. Un système de paiement pour \(W\) donne à chaque votant des paiements \(p_{ic} \geq 0\) vers ses élus approuvés et une réserve \(r_i = 1 - \sum_c p_{ic} \geq 0\), avec deux contraintes :
chaque votant paie au plus 1 au total (budget) ;
chaque élu \(c \in W\) perçoit au plus \(q\) au total (tarif d’un siège).
Théorème 3.3 (certificat).\(W\) satisfait core+ (un renforcement fractionnaire du core) si et seulement s’il existe un système de paiement avec
\(p_{iw} \leq r_i\) pour tout élu approuvé \(w\) — personne ne paie un élu plus cher que ce qu’il garde en réserve ;
pour chaque perdant \(c \notin W\) : \(\sum_{i : c \in A_i} r_i < q\) — les réserves des partisans de tout perdant ne suffisent pas à financer un siège.
C’est une preuve positive de stabilité : exhiber les paiements suffit, plus besoin d’énumérer les coalitions. Vérifions sur le fil rouge.
def verifie_certificat(A, k, W, pay, q=None):"""pay : dict (i, c) -> montant. Retourne (ok, diagnostics).""" n =len(A) q = q if q isnotNoneelse n / k W =frozenset(W) diag = [] ok =Truefor i inrange(n): total =sum(pay.get((i, c), 0.0) for c in W if c in A[i]) r_i =1.0- totalif r_i <-1e-9: ok =False; diag.append(f"v{i+1} paie {total:.3f} > 1 (budget)")for c in W:if c in A[i] and pay.get((i, c), 0.0) > r_i +1e-9: ok =False; diag.append(f"v{i+1} paie {c} plus cher que sa reserve")for c insorted(set().union(*A) - W): somme =sum(1.0-sum(pay.get((i, w), 0.0) for w in W if w in A[i])for i inrange(n) if c in A[i])if somme >= q -1e-9: ok =False diag.append(f"perdant {c} : reserves de ses partisans = {somme:.3f} >= q = {q:.1f}")return ok, diag# Certificat pour W = {a, b} : v1 et v2 paient (1/3, 1/3) chacun, reserve 1/3pay_ab = {(0, 'a'): 1/3, (0, 'b'): 1/3, (1, 'a'): 1/3, (1, 'b'): 1/3}ok_cert, diag = verifie_certificat(A, K, "ab", pay_ab)print(f"Certificat de W = {{a, b}} (paiements 1/3, 1/3 ; reserve 1/3) : "f"{'VALIDE'if ok_cert else'INVALIDE'}")for d in diag:print(" ", d)print("Charge de 'a' :", 2/3, "<= q = 2 ; reserves des partisans de c : 1.0 < 2 ; de d : 1.0 < 2")
Certificat de W = {a, b} (paiements 1/3, 1/3 ; reserve 1/3) : VALIDE
Charge de 'a' : 0.6666666666666666 <= q = 2 ; reserves des partisans de c : 1.0 < 2 ; de d : 1.0 < 2
Lecture. Avec \(\{a, b\}\) : \(v_1\) et \(v_2\) répartissent leur budget en trois parts égales (deux paiements, une réserve) — chaque paiement \(1/3 \leq\) réserve \(1/3\) ✓ ; chaque élu est financé à \(2/3 < q = 2\) ✓ ; les partisans de chaque perdant (\(c\) : seulement \(v_3\) de réserve 1 ; \(d\) : seulement \(v_4\)) totalisent \(1 < 2\) ✓. Personne ne peut se payer un siège de rechange : le certificat tient, \(\{a, b\}\) est core+ — donc core.
4. L’entropie harmonique : mesurer l’équité des paiements
Le papier définit une entropie harmonique\(F\) sur les distributions de probabilité, cousine de l’entropie de Shannon mais adaptée aux paiements. Pour \(x \in \Delta^d\), on trie les coordonnées \(x_{(1)} \geq \dots \geq x_{(d)}\), soit \(S_t(x)\) la masse des \(t\) plus grandes, et
Interprétation water-filling : \(f_\ell(x)\) est le niveau \(\tau\) auquel rabaisser les grandes coordonnées libère exactement assez de masse pour créer \(\ell\) nouvelles coordonnées de taille \(\tau\). Propriétés clés :
Lecture. Le niveau pointillé \(f_1(x) = 3/10\) est exactement la hauteur où la masse retirée aux deux grandes barres (\(1/2 - 3/10\) et \(2/5 - 3/10\)) remplit la nouvelle coordonnée à hauteur \(3/10\). L’entropie harmonique récompense ce ré-étalement : répartir le budget d’un votant uniformément entre ses élus approuvés et sa réserve maximise \(F\) — c’est le mécanisme par lequel la règle ci-dessous pousse naturellement vers l’équité.
5. La règle : maximiser l’entropie harmonique des paiements
où \(p_i\) concatène les paiements de \(i\) à ses élus approuvés et \(r_i\) sa réserve — un vecteur de \(|A_i \cap W| + 1\) coordonnées. La règle retourne \(\arg\max_{|W| = k} \mathcal{V}(W)\). Chaque \(F\) est concave, la maximisation interne est un programme concave (résoluble en temps polynomial — c’est le corollaire algorithmique du papier) ; ici, SLSQP multi-départ suffit à l’échelle de jouet.
Théorème (annoncé).Tout optimum local — à plus forte raison global — de \(\mathcal{V}\) est dans le core+. La règle ne peut donc jamais retourner un comité bloqué.
def V(A, W, q=None, n_starts=3):"""V(W) : max de sum F(p_i, r_i) sur les systemes de paiement. Concave ; SLSQP multi-depart (projection simplexe pour les iteres infaisables).""" n =len(A) k =len(W) q = q if q isnotNoneelse n / k W =list(W) idx = [[W.index(c) for c in W if c in A[i]] for i inrange(n)]def unpack(v):return v.reshape(n, k)def negobj(v): P = unpack(v) s =0.0for i inrange(n): pay = P[i, idx[i]] if idx[i] else np.array([]) vec = np.clip(np.append(np.clip(pay, 0.0, None), 1.0- P[i].sum()), 0.0, None) tot = vec.sum()if tot <1e-9ornot np.isfinite(vec).all():continue s += F(vec / tot)return-s cons = [ {"type": "ineq", "fun": lambda v: 1.0- unpack(v).sum(axis=1)}, {"type": "ineq", "fun": lambda v: np.array([q - unpack(v)[ [i for i inrange(n) if c in A[i]], j].sum() for j, c inenumerate(W)])}, {"type": "ineq", "fun": lambda v: v}, ] best =Nonefor _ inrange(n_starts): x0 = rng.dirichlet(np.ones(k), size=n).ravel() *0.5 r = minimize(negobj, x0, method="SLSQP", constraints=cons, options={"maxiter": 300, "ftol": 1e-10}) best = r.fun if best isNoneelsemin(best, r.fun)return-best# Tous les comites de taille 2 du fil rougeresultats = {}for W in itertools.combinations(CANDS, K): Wf =frozenset(W) ok, _ = is_core(A, K, Wf) resultats["".join(W)] = (V(A, Wf), ok)for W, (v, ok) insorted(resultats.items(), key=lambda kv: -kv[1][0]):print(f"V({{{W}}}) = {v:.4f} core : {ok}")best =max(resultats, key=lambda w: resultats[w][0])print(f"\nRegle (argmax) : {{{best}}} — core : {resultats[best][1]}")
Lecture. Tout comité contenant \(a\) ou \(b\) atteint \(\mathcal{V} = 3.0\) (égalité analytique : deux votants « riches » à 3 coordonnées valent 1.5 chacun, ou trois votants à 2 coordonnées valent 1 chacun), et le seul comité non-core\(\{c, d\}\) plonge à 2.0. La règle écarte le comité bloqué sans jamais regarder un blocage : c’est l’objectif entropique qui le pénalise automatiquement (les réserves inexployées de \(v_1, v_2\) concentrent leur vecteur de paiement et détruisent leur \(F\)).
Remarque d’honnêteté : le théorème garantit que tout argmax est core, pas qu’il soit unique — ici cinq comités ex æquo, tous cores.
6. Expérimentation : la règle contre les règles usuelles
une instance structurée à deux blocs — le cas où la théorie prédit l’échec d’AV : deux groupes de 3 votants aux bulletins disjoints \(\{a, b\}\) et \(\{c, d\}\), \(k = 2\), quota \(q = 3\). Chaque bloc mérite un siège ; un comité monopolisé par un bloc laisse l’autre avec un témoin de blocage évident. Comparons AV (approbation simple), PAV (propositionnelle de Thiele) et la règle entropique.
def regle_AV(A, k): cands =sorted(set().union(*A)) scores = {c: sum(c in A[i] for i inrange(len(A))) for c in cands}returnfrozenset(sorted(cands, key=lambda c: (-scores[c], c))[:k])def regle_PAV(A, k):"""PAV (Thiele) : maximise sum_i H_{|A_i inter W|} par enumeration.""" cands =sorted(set().union(*A)) best, best_s =None, -1.0for W in itertools.combinations(cands, k): s =0.0for i inrange(len(A)): t =len(frozenset(W) & A[i]) s +=sum(1.0/ j for j inrange(1, t +1))if s > best_s +1e-12: best_s, best = s, frozenset(W)return bestdef regle_entropique(A, k): cands =sorted(set().union(*A)) best, best_v =None, -1.0for W in itertools.combinations(cands, k): v = V(A, frozenset(W))if v > best_v +1e-9: best_v, best = v, frozenset(W)return bestimport randomrandom.seed(0)stats = {"AV": 0, "PAV": 0, "Entropique": 0}n_inst =0print(f"{'inst':>4}{'AV':>8}{'core':>5}{'PAV':>8}{'core':>5}{'Entrop':>8}{'core':>5}")for inst inrange(30): n = random.randint(4, 6); m = random.randint(4, 6); k = random.randint(2, 3) Ai = [frozenset(c for c inrange(m) if random.random() <0.5) for _ inrange(n)]ifany(not a for a in Ai):continue n_inst +=1 votes = {}for nom, regle in [("AV", regle_AV), ("PAV", regle_PAV), ("Entropique", regle_entropique)]: W = regle(Ai, k) ok, _ = is_core(Ai, k, W) votes[nom] = ("".join(map(str, sorted(W))), ok)if ok: stats[nom] +=1if n_inst <=8:print(f"{inst:>4}{votes['AV'][0]:>8}{str(votes['AV'][1]):>5} "f"{votes['PAV'][0]:>8}{str(votes['PAV'][1]):>5} "f"{votes['Entropique'][0]:>8}{str(votes['Entropique'][1]):>5}")print(f"\nSur {n_inst} instances : comite retourne DANS le core -> "f"AV {stats['AV']}/{n_inst} · PAV {stats['PAV']}/{n_inst} · "f"Entropique {stats['Entropique']}/{n_inst}")# Instance structuree a deux blocs : la ou AV doit echouerA2 = [frozenset("ab")] *3+ [frozenset("cd")] *3k2, q2 =2, 6/2print(f"\nDeux blocs : 3x{{a,b}} + 3x{{c,d}} (n=6, k=2, q=3)")for nom, regle in [("AV", regle_AV), ("PAV", regle_PAV), ("Entropique", regle_entropique)]: W = regle(A2, k2) ok, temoin = is_core(A2, k2, W, q=q2) ligne =f" {nom:>10} -> {sorted(W)} core : {ok}"ifnot ok: Np, T = temoin ligne +=f" (bloque par N' = votants {Np}, T = {T})"print(ligne)
Lecture. Sur le balayage aléatoire à bulletins gras (\(p = 0{,}5\)), les trois règles restent core sur tout l’échantillon — des bulletins qui se chevauchent beaucoup rendent le blocage difficile à cette échelle : signal faible (l’absence d’échec AV ici ne contredit pas la théorie — AV ne garantit pas EJR). L’instance à deux blocs montre l’échec prédit : AV, à égalité parfaite d’approbations, tranche alphabétiquement et monopolise — le second bloc (3 votants = le quota exact) obtient le témoin \(T = \{c\}\) et bloque. PAV et la règle entropique partagent les sièges. La règle entropique n’échoue jamais sur cet échantillon — illustration empirique (partielle, jouet — pas une preuve) du théorème annoncé : tout du théorème annoncé : tout argmax de \(\mathcal{V}\) est core.
Ce que ce jouet ne montre pas. Le résultat du papier est une garantie pour toute instance ; notre balayage n’est qu’une fumée empirique. La preuve elle-même (20 pages, argument d’échange type PAV sur les bornes d’ajout/retrait de candidats) n’est pas reproduite ici — voir l’encart final pour sa version vérifiée en Lean.
7. Trois encarts de mise en perspective
7.1 Core électoral et cœur coopératif : même mot, deux mondes
Le cœur d’un jeu coopératif transférable (GT-27 Kuhn-Munkres, jeu d’affectation de Shapley-Shubik) : aucune coalition ne peut garantir à ses membres plus que ce que le grand coalition leur alloue. Le core électoral ci-dessus : aucun groupe assez gros ne peut se construire un comité strictement meilleur. Dans les deux cas le cœur exprime l’absence de dévitation rentable par coalition — mais les mondes diffèrent : utilités monétaires transférables d’un côté, préférences binaires non transférables de l’autre, et un comité de taille fixe \(k\) contre des imputations libres. Le notebook GameTheory-15b (jeux coopératifs) et GT-27 sont le pendant transférable de ce notebook.
7.2 La preuve est déjà vérifiée en Lean : ABCVotingLean
Peters annonce dans l’introduction : le théorème d’existence (Hare) a été vérifié formellement en Lean dans son projet ABCVotingLean. Notre dépôt déjà une dépendance du même auteur — la visite guidée GameTheory/SocialChoice/social_choice_lean_peters/ (pinnée sur DominikPeters/SocialChoiceLean) couvre Gibbard-Satterthwaite, Duggan-Schwartz et quatre impossibilités de Condorcet. Le chemin d’upgrade est ouvert : quand ABCVotingLean publie son module core, le tour peut le suivre — le concept que ce notebook enseigne en Python existe déjà en Lean chez l’auteur dont nous dépendons.
7.3 Réflexif : une preuve majeure obtenue avec GPT-6 Astra
Le champ Comments du preprint indique « The proof was obtained with GPT-6 Astra » — quelques semaines après la preuve d’Odin sur Komlós (notebook Search, #15944). Deux traités majeurs obtenus par des agents IA en quelques semaines changent le statut épistémologique de « preprint sans validation » : le reflexe correct reste le même (citer la preuve annoncée, attendre la validation), mais la vérification formelle Lean arrive avant la validation sociale — l’ordre habituel s’inverse.
Exercices
Les trois exercices suivants utilisent le fil rouge et les fonctions des sections précédentes (is_core, V, regle_AV, regle_PAV).
Exercice 1 — Le quota de Droop est plus exigeant
Le vérificateur is_core accepte un paramètre q. Le quota de Droop (\(q = n/(k+1)\)) rend le core plus difficile à satisfaire : plus de coalitions atteignent le seuil.
Vérifiez que \(\{a, b\}\) reste core au quota de Droop sur le fil rouge.
Construisez (à la main ou par énumération) une petite instance où un comité est core au quota de Hare mais plus au quota de Droop.
Le papier prétend que l’existence vaut aussi pour Droop — votre règle entropique (V accepte aussi q) retourne-t-elle un comité Droop-core sur votre instance ?
Exercice 2 — JR : quand l’approbation simple ignore une minorité
JR (juste représentation) : si un votant n’approuve aucun élu, un groupe d’au moins \(q\) votants partageant un candidat approuvé non élu doit exister. Violer JR revient à laisser une minorité compacte sans aucune représentation.
Écrivez viole_JR(A, k, W) qui retourne le témoin (votant sans élu + groupe + candidat) ou None.
Sur le fil rouge, regle_AV peut-elle retourner un comité violant JR ? Testez sur les instances de la section 6.
Combien d’instances de la section 6 font échouer AV sur JR ?
Exercice 3 — Profils conjonctifs : « ET » casse-t-il la règle ?
Nos votants approuvent des ensembles arbitraires, mais les bulletins réels sont souvent conjontoires (« je veux une salle ET une scène », pas 2 salles). Le dataset conj du papier encode exactement cela.
Construisez un profil conjonctif FR à 6 votants (ex. : 3 types de compétences à élire, chaque votant approuve une paire complémentaire).
La règle entropique retourne-t-elle un comité core ? Un comité AV ?
Un groupe peut-il bloquer avec un \(T\)disjoint de \(W\) ? Que dit le certificat de paiement (section 3) dans ce cas ?
# Exercice 3 — a completer# A3 = [frozenset("mp"), frozenset("mp"), frozenset("sj"), ...]# best = regle_entropique(A3, 3)# print(is_core(A3, 3, best))pass
Conclusion
Le core est le sommet de la hiérarchie JR → EJR → FJR → core : une garantie de stabilité par coalitions, vérifiable par énumération à l’échelle de jouet (is_core) et certifiable à toute échelle par un système de paiements (théorème 3.3).
L’entropie harmonique\(F\) mesure l’étalement des paiements ; la règle \(\arg\max_W \mathcal{V}(W)\) du papier transforme cette mesure en règle de vote dont tout optimum est core — confirmé ici empiriquement sur une quinzaine d’instances jouets, et prouvé (annoncé ; déjà vérifié en Lean dans ABCVotingLean) pour toute instance.
La même notion de cœur traverse le cours : Shapley-Shubik et Kuhn-Munkres côté coopératif (GT-27, 15b), Arrow et Gibbard côté axiomatique (01, 05) — le core est leur extension naturelle aux groupes.
Références. Becker, Greger & Peters, Existence of the Core in Approval-Based Committee Elections, arXiv:2609.11912 (2026, preprint) · Peters, ABCVotingLean (github.com/DominikPeters/ABCVotingLean) · notebooks de la série : 01-Arrow, 03-Voting-Methods, 04-SAT-Z3, GT-27 Kuhn-Munkres, GameTheory-15b CooperativeGames.