Cette cellule initialise la JVM et détecte les outils externes nécessaires pour certains modules de TweetyProject.
Composants initialisés: - JVM avec JPype: Interface Python-Java pour accéder aux classes Tweety - JDK portable: Zulu OpenJDK 17 (auto-détecté dans jdk-17-portable/) - JARs Tweety: fichiers JAR chargés depuis libs/ - Outils externes: Clingo (ASP), SPASS (Modal), EProver (FOL), pySAT, MARCO
Note: Cette initialisation est partagée par tous les notebooks de la série Tweety via le module tweety_init.py.
Partie 7 : Préférences et Agrégation
La théorie des préférences est fondamentale en choix social, économie et argumentation. TweetyProject fournit des outils pour représenter et agréger les préférences individuelles en préférences collectives.
7.1 Ordres de Préférence
Un ordre de préférence est une relation binaire sur un ensemble d’alternatives, généralement: - Totale: Toutes les paires sont comparables - Transitive: Si A > B et B > C, alors A > C - Antisymétrique: Si A > B, alors non B > A
TweetyProject représente les préférences via: - PreferenceOrder<T>: Ordre de préférence sur des éléments de type T - BinaryRelation: Relation binaire de base - ranking.RankingFunction: Fonction de classement
Sous-modules disponibles: - io.POParser / io.POWriter: Parsing et écriture d’ordres de préférence - aggregation.*: Agrégateurs de préférences (Borda, Plurality, Veto) - ranking.*: Fonctions de ranking et leveling - update.*: Mise à jour dynamique des préférences
Note: Les règles classiques comme Copeland ne sont pas implémentées nativement dans Tweety, mais peuvent être simulées en Python (voir section suivante).
# --- 7.1 Ordres de Préférence ---print("\n--- 7.1 Ordres de Preference ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Exploration du module preferences...") prefs_imports_ok =Falsetry:import jpypefrom jpype.types import*# Exploration du package preferencesprint("\n--- Exploration du package org.tweetyproject.preferences ---")# Classes existantes dans Tweety 1.29 (noms corrects)# Note: BordaRule/CopelandRule n'existent pas - utiliser BordaScoringPreferenceAggregator# Note: PreferenceParser n'existe pas - utiliser io.POParser (Preference Order Parser) known_classes = ["PreferenceOrder", # Ordre de preference principal"BinaryRelation", # Relation binaire de base"Relation", # Interface relation"ranking.Functions", # Fonctions de ranking"ranking.LevelingFunction", # Fonction de nivellement"ranking.RankingFunction", # Fonction de classement"io.POParser", # Parser d'ordres de preference (pas PreferenceParser)"io.POWriter", # Writer d'ordres de preference"update.Update", # Mise a jour de preferences"aggregation.PreferenceAggregator", # Interface aggregation"aggregation.ScoringPreferenceAggregator", # Base pour scoring"aggregation.BordaScoringPreferenceAggregator", # Borda (pas BordaRule)"aggregation.PluralityScoringPreferenceAggregator", # Plurality"aggregation.VetoScoringPreferenceAggregator", # Veto ]print("Classes du module preferences:") found_classes = []for cls_name in known_classes:try: full_name =f"org.tweetyproject.preferences.{cls_name}" cls = jpype.JClass(full_name)print(f" [OK] {cls_name}") found_classes.append(cls_name)exceptException:print(f" [--] {cls_name} (non trouve)")if found_classes: prefs_imports_ok =Trueprint(f"\n{len(found_classes)} classes trouvees.")else:print("\nAucune classe preferences trouvee - le JAR peut etre manquant.")# Note sur les classes non implementeesprint("""Note sur les regles de vote:- Tweety implemente Borda via BordaScoringPreferenceAggregator- Copeland n'est PAS implemente nativement dans Tweety- La simulation Python ci-dessous illustre ces concepts""")# --- Exemple conceptuel de préférences ---if prefs_imports_ok:print("\n--- Exemple Conceptuel: Election ---")print("""Scenario: 3 votants, 4 candidats (A, B, C, D)Preferences des votants:- Votant 1: A > B > C > D- Votant 2: B > C > D > A - Votant 3: C > D > A > BQuestions d'agregation:1. Quel candidat devrait gagner selon Borda?2. Y a-t-il un gagnant de Condorcet?3. Que donne la regle de Copeland?Ces questions sont au coeur de la theorie du choix socialet du theoreme d'impossibilite d'Arrow.""")exceptExceptionas e_gen:print(f"Erreur Python inattendue: {e_gen}")import traceback; traceback.print_exc()
--- 7.1 Ordres de Preference ---
JVM prete. Exploration du module preferences...
--- Exploration du package org.tweetyproject.preferences ---
Classes du module preferences:
[OK] PreferenceOrder
[OK] BinaryRelation
[OK] Relation
[OK] ranking.Functions
[OK] ranking.LevelingFunction
[OK] ranking.RankingFunction
[OK] io.POParser
[OK] io.POWriter
[OK] update.Update
[OK] aggregation.PreferenceAggregator
[OK] aggregation.ScoringPreferenceAggregator
[OK] aggregation.BordaScoringPreferenceAggregator
[OK] aggregation.PluralityScoringPreferenceAggregator
[OK] aggregation.VetoScoringPreferenceAggregator
14 classes trouvees.
Note sur les regles de vote:
- Tweety implemente Borda via BordaScoringPreferenceAggregator
- Copeland n'est PAS implemente nativement dans Tweety
- La simulation Python ci-dessous illustre ces concepts
--- Exemple Conceptuel: Election ---
Scenario: 3 votants, 4 candidats (A, B, C, D)
Preferences des votants:
- Votant 1: A > B > C > D
- Votant 2: B > C > D > A
- Votant 3: C > D > A > B
Questions d'agregation:
1. Quel candidat devrait gagner selon Borda?
2. Y a-t-il un gagnant de Condorcet?
3. Que donne la regle de Copeland?
Ces questions sont au coeur de la theorie du choix social
et du theoreme d'impossibilite d'Arrow.
Interprétation: Structure du module préférences
La sortie ci-dessus révèle l’architecture du module org.tweetyproject.preferences:
Classes de base (représentation): - PreferenceOrder: Ordre de préférence principal - BinaryRelation / Relation: Relations binaires génériques - ranking.RankingFunction / LevelingFunction: Fonctions de classement et nivellement
Entrées/Sorties: - io.POParser / io.POWriter: Lecture et écriture d’ordres de préférence au format texte
Agrégation: - aggregation.PreferenceAggregator: Interface générique - aggregation.BordaScoringPreferenceAggregator: Implémentation de Borda - aggregation.PluralityScoringPreferenceAggregator: Règle de pluralité - aggregation.VetoScoringPreferenceAggregator: Règle de veto
Mise à jour: - update.Update: Mise à jour dynamique des préférences (révision)
Limitation importante: Tweety n’implémente pas nativement les règles de Condorcet et Copeland. Ces concepts seront illustrés via des simulations Python dans la section suivante.
7.2 Règles d’Agrégation de Préférences
Les règles de vote transforment un profil de préférences individuelles en un résultat collectif. Les principales règles implémentées ou conceptualisées dans TweetyProject:
Règles de score: - Borda: Chaque position dans un classement donne des points - Plurality: Seul le premier choix compte
Règles de Condorcet: - Condorcet: Le gagnant bat tous les autres en duel - Copeland: Score = victoires en duels - défaites - Kemeny-Young: Minimise la distance aux préférences individuelles
Théorème d’Arrow: Aucune règle d’agrégation ne peut satisfaire simultanément: unanimité, indépendance des alternatives non pertinentes, et non-dictature (pour 3+ alternatives).
Origine. Le théorème d’impossibilité d’Arrow est démontré par Arrow, K. J. (1951), Social Choice and Individual Values, New York: Wiley (Cowles Foundation Monograph ; 2e éd. 1963) — résultat fondateur de la théorie du choix social pour lequel Arrow reçoit le prix Nobel d’économie en 1972. Il établit qu’aucune fonction d’agrégation des préférences individuelles (sur 3+ alternatives) ne peut satisfaire simultanément quatre conditions apparemment raisonnables (universalité, unanimité/Pareto, indépendance des alternatives non pertinentes, non-dictature).
# --- 7.2 Règles d'Agrégation de Préférences ---print("\n--- 7.2 Regles d'Agregation de Preferences ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Demonstration des regles de vote...")# Simulation Python des règles de base (indépendant de Tweety)print("\n--- Simulation Python des Regles de Vote ---")# Données: préférences de 5 votants sur 4 candidats candidates = ['A', 'B', 'C', 'D']# Chaque liste représente le classement d'un votant (du meilleur au pire) preferences = [ ['A', 'B', 'C', 'D'], # Votant 1 ['A', 'C', 'B', 'D'], # Votant 2 ['B', 'C', 'D', 'A'], # Votant 3 ['C', 'B', 'D', 'A'], # Votant 4 ['D', 'C', 'B', 'A'], # Votant 5 ]print(f"Candidats: {candidates}")print(f"Nombre de votants: {len(preferences)}")print("\nPreferences individuelles:")for i, pref inenumerate(preferences, 1):print(f" Votant {i}: {' > '.join(pref)}")# Règle de Bordaprint("\n--- Regle de Borda ---") borda_scores = {c: 0for c in candidates} n =len(candidates)for pref in preferences:for rank, candidate inenumerate(pref): borda_scores[candidate] += (n -1- rank) # n-1 points pour le 1er, 0 pour le dernierprint("Scores Borda (points):")for c, score insorted(borda_scores.items(), key=lambda x: -x[1]):print(f" {c}: {score} points") borda_winner =max(borda_scores, key=borda_scores.get)print(f"Gagnant Borda: {borda_winner}")# Méthode de Condorcetprint("\n--- Methode de Condorcet ---")# Compter les victoires en duelsdef pairwise_comparison(c1, c2, preferences):"""Compte combien de votants préfèrent c1 à c2""" count =0for pref in preferences:if pref.index(c1) < pref.index(c2): count +=1return count condorcet_matrix = {}for c1 in candidates: condorcet_matrix[c1] = {}for c2 in candidates:if c1 != c2: condorcet_matrix[c1][c2] = pairwise_comparison(c1, c2, preferences)print("Matrice des duels (lignes battent colonnes):")print(" "+" ".join(candidates))for c1 in candidates: row = [str(condorcet_matrix[c1].get(c2, '-')).center(2) for c2 in candidates]print(f" {c1}{' '.join(row)}")# Chercher le gagnant de Condorcet condorcet_winner =Nonefor c in candidates: wins_all =all(condorcet_matrix[c].get(other, 0) >len(preferences)//2for other in candidates if other != c)if wins_all: condorcet_winner = cbreakif condorcet_winner:print(f"Gagnant de Condorcet: {condorcet_winner} (bat tous les autres en duel)")else:print("Pas de gagnant de Condorcet (cycle de Condorcet probable)")# Règle de Copelandprint("\n--- Regle de Copeland ---") copeland_scores = {c: 0for c in candidates}for c1 in candidates:for c2 in candidates:if c1 != c2:if condorcet_matrix[c1][c2] > condorcet_matrix[c2][c1]: copeland_scores[c1] +=1elif condorcet_matrix[c1][c2] < condorcet_matrix[c2][c1]: copeland_scores[c1] -=1print("Scores Copeland (victoires - defaites):")for c, score insorted(copeland_scores.items(), key=lambda x: -x[1]):print(f" {c}: {score:+d}") copeland_winner =max(copeland_scores, key=copeland_scores.get)print(f"Gagnant Copeland: {copeland_winner}")
--- 7.2 Regles d'Agregation de Preferences ---
JVM prete. Demonstration des regles de vote...
--- Simulation Python des Regles de Vote ---
Candidats: ['A', 'B', 'C', 'D']
Nombre de votants: 5
Preferences individuelles:
Votant 1: A > B > C > D
Votant 2: A > C > B > D
Votant 3: B > C > D > A
Votant 4: C > B > D > A
Votant 5: D > C > B > A
--- Regle de Borda ---
Scores Borda (points):
C: 10 points
B: 9 points
A: 6 points
D: 5 points
Gagnant Borda: C
--- Methode de Condorcet ---
Matrice des duels (lignes battent colonnes):
A B C D
A - 2 2 2
B 3 - 2 4
C 3 3 - 4
D 3 1 1 -
Gagnant de Condorcet: C (bat tous les autres en duel)
--- Regle de Copeland ---
Scores Copeland (victoires - defaites):
C: +3
B: +1
D: -1
A: -3
Gagnant Copeland: C
Analyse comparative des règles de vote
Les résultats ci-dessus illustrent la coherence entre différentes méthodes d’agregation :
Convergence des résultats : - Borda : C gagne avec 10 points (consensus) - Condorcet : C est le gagnant absolu (bat tous les autres en duel) - Copeland : C a le score maximal +3 (3 victoires, 0 defaite)
Dans cet exemple, les trois règles convergent vers le même gagnant (C), ce qui renforce la legitimite du résultat.
Matrice des duels - lecture :
A B C D
C 3 3 - 4 <- C bat A (3-2), B (3-2), D (4-1)
C bat A : 3 votants preferent C a A, 2 preferent A a C
C bat B : 3 votants preferent C a B, 2 preferent B a C
C bat D : 4 votants preferent C a D, 1 prefere D a C
Cas interessants : 1. Gagnant de Condorcet : C existe ici, mais n’existe pas toujours (cycles possibles) 2. Scores Borda : C (10) > B (9) > A (6) > D (5) - l’ecart B-C est faible 3. Paradoxe potentiel : Si on ajoutait un 6e votant avec préférences stratégiques, le résultat pourrait changer
Theoreme d’Arrow : Ce résultat coherent ne contredit pas Arrow : le theoreme concerne l’impossibilite de satisfaire TOUS les critères pour TOUS les profils de préférences.
7.3 Lien avec l’Argumentation
Les préférences sont liées à l’argumentation de plusieurs façons:
Préférences sur arguments: Ordre de préférence sur la crédibilité des arguments
Argumentation sociale: Les votes dans les SAF sont une forme d’agrégation de préférences
Résolution de conflits: Les préférences permettent de trancher entre extensions
Dans TweetyProject, le module arg.social (Tweety-7a) utilise des concepts de préférences pour pondérer l’acceptabilité des arguments.
# --- 7.3 Lien avec l'Argumentation ---print("\n--- 7.3 Lien avec l'Argumentation ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Demonstration du lien preferences-argumentation...")try:import jpypefrom jpype.types import*from org.tweetyproject.arg.dung.syntax import DungTheory, Argument, Attackfrom org.tweetyproject.arg.dung.reasoner import SimplePreferredReasoner, SimpleGroundedReasonerprint("\n--- Scenario: Preferences sur Arguments ---")print("""Un debat avec 3 arguments:- A: "Le projet est rentable" (soutenu par le directeur financier)- B: "Le projet est risque" (soutenu par l'expert technique)- C: "Le risque est acceptable" (soutenu par le consultant)Relations:- A attaque B (rentabilite vs risque)- B attaque A (risque vs rentabilite)- C attaque B (minimise le risque)Question: Comment les preferences des decideurs influencent le resultat?""")# Créer le framework theory = DungTheory() a = Argument("rentable"); b = Argument("risque"); c = Argument("risque_acceptable") theory.add(a); theory.add(b); theory.add(c) theory.add(Attack(a, b)); theory.add(Attack(b, a)); theory.add(Attack(c, b))print(f"Framework: {theory}")# Calculer les extensions gr_reasoner = SimpleGroundedReasoner() pref_reasoner = SimplePreferredReasoner() grounded = gr_reasoner.getModel(theory) preferred = pref_reasoner.getModels(theory)print(f"\nExtension Grounded: {grounded}")print(f"Extensions Preferees: {preferred}")print("""Interpretation:- Sans preferences, l'extension grounded inclut C (risque_acceptable)- C defend indirectement A contre B- Si les decideurs preferent les arguments de l'expert technique (B), ils pourraient utiliser un framework pondere (WAF) pour ajuster les poids- Voir Tweety-7a pour l'implementation des WAF""")exceptExceptionas e:print(f"Erreur: {e}")import traceback; traceback.print_exc()
--- 7.3 Lien avec l'Argumentation ---
JVM prete. Demonstration du lien preferences-argumentation...
--- Scenario: Preferences sur Arguments ---
Un debat avec 3 arguments:
- A: "Le projet est rentable" (soutenu par le directeur financier)
- B: "Le projet est risque" (soutenu par l'expert technique)
- C: "Le risque est acceptable" (soutenu par le consultant)
Relations:
- A attaque B (rentabilite vs risque)
- B attaque A (risque vs rentabilite)
- C attaque B (minimise le risque)
Question: Comment les preferences des decideurs influencent le resultat?
Framework: <{ rentable, risque, risque_acceptable },[(rentable,risque), (risque_acceptable,risque), (risque,rentable)]>
Extension Grounded: {rentable,risque_acceptable}
Extensions Preferees: [{rentable,risque_acceptable}]
Interpretation:
- Sans preferences, l'extension grounded inclut C (risque_acceptable)
- C defend indirectement A contre B
- Si les decideurs preferent les arguments de l'expert technique (B),
ils pourraient utiliser un framework pondere (WAF) pour ajuster les poids
- Voir Tweety-7a pour l'implementation des WAF
Résumé
Ce notebook a couvert la théorie des préférences et son lien avec l’argumentation:
Concept
Description
Implémentation
Ordres de préférence
Relations binaires transitives sur alternatives
PreferenceOrder<T>
Borda
Score par position dans le classement
Simulation Python
Condorcet
Gagnant qui bat tous les autres en duel
Matrice des duels
Copeland
Score = victoires - défaites en duels
Simulation Python
Théorème d’Arrow
Impossibilité d’agrégation parfaite
Résultat théorique
Points clés
Borda favorise les candidats consensuels (bien classés par tous)
Condorcet cherche un gagnant absolu (peut ne pas exister - cycles)
Copeland est robuste quand il n’y a pas de gagnant de Condorcet
Les préférences sur arguments permettent de résoudre les conflits dans les frameworks abstraits
Conclusion de la Série Tweety
Cette série de notebooks couvre les principaux modules de TweetyProject 1.28:
#
Notebook
Thème
Modules
1
Setup
Configuration JVM/JPype
commons, JARs
2
Basic-Logics
Logique propositionnelle et FOL
logics.pl, logics.fol
3
Advanced-Logics
DL, Modal, QBF, Conditional
logics.dl, ml, qbf, cl
4
Belief-Revision
Révision de croyances, MUS
beliefdynamics, logics.pl
5
Abstract-Argumentation
Dung, CF2, génération
arg.dung
6
Structured-Argumentation
ASPIC+, DeLP, ABA, ASP
arg.aspic, delp, aba, lp
7a
Extended-Frameworks
ADF, Bipolar, WAF, SAF, SetAF
arg.adf, bipolar, weighted, social
7b
Ranking-Probabilistic
Classement, probabilités
arg.rankings, arg.prob
8
Agent-Dialogues
Multi-agents, protocoles
agents, agents.dialogues
9
Préférences
Agrégation, vote
préférences
Limitations connues
ADF: Nécessite solveur SAT natif (non disponible via JPype)
SimpleMlReasoner: Peut bloquer sans SPASS installé
FOL avec égalité: Utiliser EProver pour éviter les timeouts
Concevez un système de vote pour un jury de 5 membres evaluant 4 projets.
Objectifs
Modeliser les préférences individuelles des jurys
Appliquer différentes règles de vote (Borda, Condorcet, Copeland)
Analyser les paradoxes et cycles potentiels
Proposer une méthode de resolution des conflits
Instructions
Définition : Créez une liste de 4 projets et un profil de préférence pour 5 membres du jury (expert technique, financier, utilisateur, environnemental, président).
Calcul de score : Implémentez la règle de Borda (chaque position donne des points décroissants).
Matrice de duels : Construisez la matrice de Condorcet pour comparer les projets deux à deux.
Détection de cycles : Identifiez si un cycle de Condorcet existe (paradoxe du vote).
Agrégation : Calculez les scores de Copeland (victoires - défaites en duels).
Questions d’analyse
Les différentes méthodes donnent-elles le même gagnant ?
Si non, quelle méthode est la plus equitable dans ce contexte ?
Comment gerer les ex aequo ?
Que se passe-t-il si un membre du jury a des préférences non transitives ?
projets = ['Projet_A', 'Projet_B', 'Projet_C', 'Projet_D']preferences_jury = [ ['Projet_A', 'Projet_B', 'Projet_C', 'Projet_D'], # Membre 1: expert technique ['Projet_B', 'Projet_C', 'Projet_D', 'Projet_A'], # Membre 2: expert financier ['Projet_C', 'Projet_D', 'Projet_A', 'Projet_B'], # Membre 3: representant utilisateur ['Projet_D', 'Projet_A', 'Projet_B', 'Projet_C'], # Membre 4: responsable environnemental ['Projet_A', 'Projet_C', 'Projet_B', 'Projet_D'], # Membre 5: president du jury]def borda_score(preferences, candidats):"""Calcule les scores Borda pour chaque candidat.""" scores = {c: 0for c in candidats} n =len(candidats)for pref in preferences:for rank, candidate inenumerate(pref): scores[candidate] += (n -1- rank)return scoresdef condorcet_matrix(preferences, candidats):"""Cree la matrice des duels par paires.""" matrix = {c1: {c2: 0for c2 in candidats if c2 != c1} for c1 in candidats}for pref in preferences:for i, c1 inenumerate(pref):for c2 in pref[i +1:]: matrix[c1][c2] +=1return matrixdef detect_cycle(matrix):"""Detecte s'il existe un cycle dans les preferences collectives.""" candidats =list(matrix.keys()) edges = {c: [] for c in candidats}for c1 in candidats:for c2, votes in matrix[c1].items():if votes > matrix[c2].get(c1, 0): edges[c1].append(c2) visited =set() rec_stack =set()def dfs(node): visited.add(node) rec_stack.add(node)for neighbor in edges[node]:if neighbor notin visited:if dfs(neighbor):returnTrueelif neighbor in rec_stack:returnTrue rec_stack.remove(node)returnFalsefor node in candidats:if node notin visited:if dfs(node):returnTruereturnFalseprint("Preferences du jury:")for i, pref inenumerate(preferences_jury, 1):print(f" Membre {i}: {' > '.join(pref)}")scores_borda = borda_score(preferences_jury, projets)gagnant_borda =max(scores_borda, key=scores_borda.get)mat = condorcet_matrix(preferences_jury, projets)n_votants =len(preferences_jury)gagnant_condorcet =Nonefor p in projets:ifall(mat[p].get(autre, 0) > n_votants //2for autre in projets if autre != p): gagnant_condorcet = pbreakscores_copeland = {p: 0for p in projets}for p1 in projets:for p2 in projets:if p1 != p2:if mat[p1][p2] > mat[p2][p1]: scores_copeland[p1] +=1elif mat[p1][p2] < mat[p2][p1]: scores_copeland[p1] -=1gagnant_copeland =max(scores_copeland, key=scores_copeland.get)cycle = detect_cycle(mat)print("\nComparaison des methodes de vote:")print(f"Borda: {gagnant_borda} (scores: {dict(sorted(scores_borda.items(), key=lambda x: -x[1]))})")print(f"Condorcet: {gagnant_condorcet if gagnant_condorcet else'Pas de gagnant (cycle detecte)'}")print(f"Copeland: {gagnant_copeland} (scores: {dict(sorted(scores_copeland.items(), key=lambda x: -x[1]))})")print(f"Cycle de Condorcet detecte: {cycle}")print("\nMatrice des duels:")print(" "+" ".join(p[-1] for p in projets))for p1 in projets: row = [str(mat[p1].get(p2, '-')).center(2) for p2 in projets]print(f" {p1[-1]}{' '.join(row)}")
Preferences du jury:
Membre 1: Projet_A > Projet_B > Projet_C > Projet_D
Membre 2: Projet_B > Projet_C > Projet_D > Projet_A
Membre 3: Projet_C > Projet_D > Projet_A > Projet_B
Membre 4: Projet_D > Projet_A > Projet_B > Projet_C
Membre 5: Projet_A > Projet_C > Projet_B > Projet_D
Comparaison des methodes de vote:
Borda: Projet_A (scores: {'Projet_A': 9, 'Projet_C': 8, 'Projet_B': 7, 'Projet_D': 6})
Condorcet: Pas de gagnant (cycle detecte)
Copeland: Projet_A (scores: {'Projet_A': 1, 'Projet_B': 1, 'Projet_C': -1, 'Projet_D': -1})
Cycle de Condorcet detecte: True
Matrice des duels:
A B C D
A - 4 3 2
B 1 - 3 3
C 2 2 - 4
D 3 2 1 -
Reponses aux questions d’analyse
Les différentes méthodes donnent-elles le même gagnant ?
Non. Borda identifie Projet_A comme vainqueur unique (9 pts vs 8 pour C).
Copeland aboutit a une egalite entre Projet_A et Projet_B (+1).
Condorcet ne donne aucun vainqueur car un cycle a ete detecte (A > B > C > D > A).
Si non, quelle méthode est la plus equitable dans ce contexte ?
Dans ce scénario de cycle, la méthode de Borda semble la plus robuste car elle reflete l’intensite globale des préférences. Elle selectionne le candidat qui fait le meilleur consensus global. Copeland est également une bonne alternative mais ne permet pas de trancher ici.
Comment gerer les ex aequo ?
On peut utiliser le vote du President du jury (Membre 5) comme departage. Ici, le Membre 5 prefere A a B, ce qui confirmerait A comme vainqueur.
Que se passe-t-il si un membre du jury a des préférences non transitives ?
Cela brise l’hypothese de rationalite individuelle. En pratique, cela rendrait impossible la modelisation par un ordre de préférence strict et augmenterait l’instabilite du vote collectif, rendant les paradoxes encore plus frequents.
Conclusion
Ce notebook a permis d’explorer les aspects essentiels de tweety 9 préférences. Les points cles :
Les concepts fondamentaux ont ete presentes et illustres
Les Exemple guides proposent une mise en pratique progressive
Les résultats obtenus permettent de valider la comprehension
Pour aller plus loin : approfondir les aspects avances du sujet et explorer les liens avec d’autres domaines.
Exemple guide : Système de vote avec préférences
Implementation complete d’un système de vote avec 4 candidats (Paris, Berlin, Rome, Madrid) et analyse des résultats selon plusieurs méthodes de vote.
# Exemple guide : Solution completecandidats = ['Paris', 'Berlin', 'Rome', 'Madrid']# 1. Definition des profils de preference (5 votants)profils = [ ['Paris', 'Berlin', 'Rome', 'Madrid'], # Votant 1 ['Berlin', 'Paris', 'Madrid', 'Rome'], # Votant 2 ['Rome', 'Madrid', 'Paris', 'Berlin'], # Votant 3 ['Madrid', 'Rome', 'Berlin', 'Paris'], # Votant 4 ['Berlin', 'Rome', 'Paris', 'Madrid'], # Votant 5]def calculate_all_rules(prefs, candidates): borda = {c: 0for c in candidates} n =len(candidates)for p in prefs:for rank, c inenumerate(p): borda[c] += (n -1- rank) plurality = {c: 0for c in candidates}for p in prefs: plurality[p[0]] +=1 condorcet_winner =Nonefor c1 in candidates: is_condorcet =Truefor c2 in candidates:if c1 == c2:continue wins =sum(1for p in prefs if p.index(c1) < p.index(c2))if wins <=len(prefs) /2: is_condorcet =Falsebreakif is_condorcet: condorcet_winner = c1breakreturn borda, plurality, condorcet_winnerprint("--- Resultats de l'exercice de synthese ---")b, p, c = calculate_all_rules(profils, candidats)b_win =max(b, key=b.get)p_win =max(p, key=p.get)print(f"Vainqueur Borda: {b_win} (scores: {dict(sorted(b.items(), key=lambda x: -x[1]))})")print(f"Vainqueur Pluralite: {p_win} ({p[p_win]} votes)")print(f"Vainqueur Condorcet: {c if c else'Aucun'}")print(f"\nConsensus (Borda == Pluralite == Condorcet): {b_win == p_win == c}")# 2. Manipulation strategiqueprint("\n--- Manipulation Strategique (Votant 3) ---")profils_manip = profils.copy()print(f"Votant 3 change son vote de {profils[2]} a ['Paris', 'Rome', 'Madrid', 'Berlin']")profils_manip[2] = ['Paris', 'Rome', 'Madrid', 'Berlin']b2, p2, c2 = calculate_all_rules(profils_manip, candidats)# Analyse derivee des donnees (pas de conclusion en dur) : on detecte les egalites# et on compare le nouveau gagnant Borda au gagnant initial pour conclure honnetement.b2_win =max(b2, key=b2.get)p2_win =max(p2, key=p2.get)max_b2 = b2[b2_win]b2_ties = [c for c in candidats if b2[c] == max_b2]max_p2 = p2[p2_win]p2_ties = [c for c in candidats if p2[c] == max_p2]print(f"Nouveau vainqueur Borda: {b2_win} (scores: {dict(sorted(b2.items(), key=lambda x: -x[1]))})")iflen(p2_ties) >1:print(f"Nouveau vainqueur Pluralite: {p2_win} (egalite a {max_p2} votes avec {sorted(p2_ties)})")else:print(f"Nouveau vainqueur Pluralite: {p2_win} ({max_p2} votes)")# Conclusion honnete : le gagnant Borda initial est-il preserve ou deplace ?if b2_win == b_win:print(f"Note: la manipulation preserve le gagnant Borda initial ({b_win}).")eliflen(b2_ties) >1:print(f"Note: la manipulation DEPLACE le gagnant Borda initial ({b_win}). "f"Elle cree une egalite a {max_b2} points entre {sorted(b2_ties)}, que la "f"regle max() tranche en faveur de {b2_win} (ordre d'insertion dans le dict) "f"-- le depouillage d'une egalite etant arbitraire, il est lui aussi manipulable.")else:print(f"Note: la manipulation deplace le gagnant Borda initial ({b_win}) au profit de {b2_win}.")
--- Resultats de l'exercice de synthese ---
Vainqueur Borda: Berlin (scores: {'Berlin': 9, 'Rome': 8, 'Paris': 7, 'Madrid': 6})
Vainqueur Pluralite: Berlin (2 votes)
Vainqueur Condorcet: Berlin
Consensus (Borda == Pluralite == Condorcet): True
--- Manipulation Strategique (Votant 3) ---
Votant 3 change son vote de ['Rome', 'Madrid', 'Paris', 'Berlin'] a ['Paris', 'Rome', 'Madrid', 'Berlin']
Nouveau vainqueur Borda: Paris (scores: {'Paris': 9, 'Berlin': 9, 'Rome': 7, 'Madrid': 5})
Nouveau vainqueur Pluralite: Paris (egalite a 2 votes avec ['Berlin', 'Paris'])
Note: la manipulation DEPLACE le gagnant Borda initial (Berlin). Elle cree une egalite a 9 points entre ['Berlin', 'Paris'], que la regle max() tranche en faveur de Paris (ordre d'insertion dans le dict) -- le depouillage d'une egalite etant arbitraire, il est lui aussi manipulable.
Exercice : Système de vote etendu
Etendez le système de vote a 6 candidats et testez si le paradoxe de Condorcet apparait.
Indice : Ajoutez Tokyo et Sydney, puis comparez Condorcet vs Borda.
# Exercice : Systeme de vote avec detection de manipulation# TODO etudiant : ajoutez 2 candidats et testez la robustesse# Etape 1 : ajouter Tokyo et Sydney aux candidats# Etape 2 : generer de nouvelles preferences# Etape 3 : verifier si le classement change selon la methodeprint("Exercice a completer")
Exercice a completer
Exercice : Agregation Borda avec l’API native de Tweety
Les règles de vote ont ete simulees en pur Python. Tweety fournit une vraie API : PreferenceOrder et BordaScoringPreferenceAggregator. Utilisez-la.
Indices :
from org.tweetyproject.preferences import PreferenceOrder
from org.tweetyproject.preferences.aggregation import BordaScoringPreferenceAggregator
Explorez l’API par introspection : for m in PreferenceOrder.class_.getMethods(): print(m.getName())
Le notebook jumeau Tweety-09-Preferences-CSharp.ipynb (.NET Interactive) couvre les memes fondements theoriques que ce notebook-ci (theorie du choix social : ordres de preference, regles d’agregation Borda 1781 / Condorcet 1785 / Copeland 1951, lien preferences-argumentation), mais selon une architecture IKVM runtime similaire a c.757 (Tweety-7b, shades transitifs BUG) et c.758 (Tweety-4, shades CLEAN), distincte de c.756 (Tweety-7a, from-scratch BCL .NET 9) :
Aspect
Python (ce notebook)
C# jumeau
Moteur
JVM Tweety via jpype (35 JARs, init_tweety())
IKVM 8.15.0 runtime (charge DLL Java org.tweetyproject.tweety-preferences.dll 7,4 Mo compilee depuis fat-jar shade Maven)
IKVM 8.15.0 + IKVM.Image (NuGet ; IKVM.Image tire le runtime natif de chaque plateforme)
Diagnostic runtime
JVM prete. Execution des exemples... (cell 1) puis JVM prete. Exploration du module preferences... (cell 5)
DLL path : ...org.tweetyproject.tweety-preferences.dll + DLL size : 7,4 Mo + Assembly chargee : org.tweetyproject.tweety-preferences v1.30.0.0 (cell 3) puis Types exposes dans org.tweetyproject.preferences avec BordaScoringPreferenceAggregator etc. (cell 6)
7.1 Ordres de preference
Code direct : PreferenceOrder(alternatives, ranking) + getElements() (cell 5)
Reflection .NET : enumeration des types exposes du JAR (BordaScoringPreferenceAggregator, CondorcetPreferenceAggregator, CopelandPreferenceAggregator, etc.) via Assembly.GetTypes() + t.IsClass (cell 6)
7.2 Regles d’agregation
3 regles executees directement : Borda (BordaScoringPreferenceAggregator), Condorcet (CondorcetPreferenceAggregator), Copeland (CopelandPreferenceAggregator) sur 4 candidats A/B/C/D avec 5 votants (cell 8)
Meme 3 regles executees via IKVM (Borda/Condorcet/Copeland), 5 votants, 4 candidats (cell 9) — meme implementation Tweety, portage direct
7.3 Lien avec argumentation
Demonstration vote par preferences + application a un framework argumentatif (Dung) pour trancher un conflit (cell 11)
Demo Dung via IKVM : chargement framework + resolution conflit par preferences (cell 12)
Exemple guide iconique
Jury 5 membres notant 4 projets A/B/C/D, affichage preferences de chaque membre puis vainqueur Borda (cell 14)
Systeme de vote Paris/Berlin/Rome/Madrid (cell 15) — exemple canonique du choix social europeen
Exercices
3 stubs : systeme de vote detection manipulation (cell 20), agregation Borda API native (cell 22), trancher conflit argumentatif par preferences (cell 24)
3 stubs : systeme de vote 6 candidats avec Tokyo/Sydney (cell 18), agregation Borda API native Tweety (cell 20), trancher conflit argumentatif (cell 22)
Algorithme commun cross-langage : la theorie du choix social classique (axiomes de Condorcet / Arrow 1951 / position dominante de Borda 1781), les regles d’agregation classiques (Borda : somme des positions, Condorcet : duels pairwise, Copeland : moyenne des duels), la structure de donnees PreferenceOrder (ordre total sur alternatives), et l’agregation multi-votants avec gestion de la manipulation (strategic voting, Gibbard-Satterthwaite 1973). Les notebooks utilisent les memes classes Java Tweety recompilees en DLL .NET (org.tweetyproject.preferences.aggregation.BordaScoringPreferenceAggregator, CondorcetPreferenceAggregator, CopelandPreferenceAggregator). La parite est sur l’algorithme de vote classique, pas sur l’exemple execute.
Substance pedagogique distincte (c.759) :
Python notebook montre l’usage direct de l’ecosysteme Tweety preferences : ordre de preference (PreferenceOrder), 3 regles d’agregation executees sur scenarios varies (4 candidats A/B/C/D 5 votants), exemple guide jury 5 membres notant 4 projets avec vainqueur Borda, 3 exercices stubs. Pedagogie de l’ecosysteme : richesse des types, accessibilite directe via jpype, richesse des JARs exposes.
C# jumeau montre qu’on peut consommer une DLL Java dans .NET via IKVM sans JVM separee, en explorant les types exposes par reflection (cellule 6 enumerant les types du JAR, pedagogie de la portabilite cross-runtime), puis en executant Borda/Condorcet/Copeland sur un systeme de vote europeen (Paris/Berlin/Rome/Madrid). Pedagogie du port cross-runtime et de la theorie du vote : focus sur l’agregation et la manipulation, avec la specificite .NET (reflection + types exposes via IKVM).
# --- Exercice : Agregation Borda avec l'API native de Tweety ---# TODO etudiant : agregez des ordres de preference avec les classes Java de Tweety## Etape 1 : imports (cf section 7.1)# from org.tweetyproject.preferences import PreferenceOrder# from org.tweetyproject.preferences.aggregation import BordaScoringPreferenceAggregator# from java.util import ArrayList## Etape 2 : explorer l'API de PreferenceOrder par introspection# Etape 3 : construire au moins 2 PreferenceOrder individuels# Etape 4 : mettre dans une ArrayList et appliquer BordaScoringPreferenceAggregator.aggregate(...)# Etape 5 : afficher l'ordre collectif resultantifnot jvm_ready:print("ERREUR: JVM non demarree.")else: aggregator =None# TODO etudiant : remplacer par le BordaScoringPreferenceAggregator resultat =None# TODO etudiant : remplacer par l'ordre collectif agregeprint("Exercice a completer")
Exercice a completer
Exercice : Trancher un conflit argumentatif par les préférences
La section 7.3 a montre le lien préférences <-> argumentation : quand deux arguments s’attaquent symetriquement, la sémantique grounded reste indecise. Une préférence permet de trancher.
Contexte
eco : “Privilegier l’economie” (attaque env)
env : “Privilegier l’environnement” (attaque eco)
En grounded, ni l’un ni l’autre n’est accepte. Ajoutez pref_env -> eco pour trancher.
Indices :
SimplePreferredReasoner().getModels(theory) liste les extensions preferred
Ajouter pref_env = Argument("pref_env") puis theory.add(Attack(pref_env, eco))
# --- Exercice : Trancher un conflit argumentatif par les preferences ---# TODO etudiant : utilisez une preference pour resoudre un conflit symetrique## Etape 1 : imports (cf section 7.3)# from org.tweetyproject.arg.dung.syntax import DungTheory, Argument, Attack# from org.tweetyproject.arg.dung.reasoner import SimpleGroundedReasoner, SimplePreferredReasoner## Etape 2 : construire le DungTheory symetrique (eco <-> env) et calculer grounded (vide)# Etape 3 : lister les extensions preferred ({eco} et {env})# Etape 4 : ajouter pref_env -> eco et recalculer grounded# Etape 5 (bonus) : modeliser eco > env et observer le basculementifnot jvm_ready:print("ERREUR: JVM non demarree.")else: theory =None# TODO etudiant : remplacer par le DungTheory symetrique grounded_avant =None# TODO etudiant : grounded avant preference (attendu : vide) grounded_apres =None# TODO etudiant : grounded apres pref_env -> ecoprint("Exercice a completer")