La cellule précédente a configure l’infrastructure complete pour l’argumentation avec Tweety :
JVM Java : Demarree avec 42 JARs Tweety charges en memoire
JDK portable : Zulu OpenJDK 17 auto-detecte
Outils externes (5/5) :
Clingo : Solveur ASP (Answer Set Programming)
SPASS : Prouveur de theoremes pour logique modale
EProver : Prouveur FOL (First-Order Logic)
pySAT : Solveurs SAT Python (CaDiCaL, Glucose)
MARCO : Enumerateur MUS avec Z3
Note technique : Ces outils ne sont pas tous utilises dans ce notebook, mais sont necessaires pour d’autres notebooks Tweety (logiques avancees, argumentation structuree ASP).
Prochaines étapes : Nous allons maintenant explorer les cadres d’argumentation abstraits de Dung.
Partie 4 : Argumentation Abstraite et Structurée
Nous entrons maintenant au cœur de l’argumentation computationnelle, en commençant par le cadre fondateur de Dung et en progressant vers des approches qui prennent en compte la structure interne des arguments. Cette partie est souvent plus stable car elle repose sur des modules centraux de Tweety.
Contexte Historique et Motivation
Le cadre d’argumentation abstraite introduit par Phan Minh Dung en 1995 a revolutionne l’étude formelle de l’argumentation. Contrairement aux approches logiques classiques, Dung s’interesse a la structure relationnelle des arguments plutot qu’a leur contenu interne.
Applications concretes : - Systèmes de decision medicale (arguments pour/contre un traitement) - Debats politiques (modelisation de positions conflictuelles) - Negociation multi-agents (protocoles d’accord) - Raisonnement juridique (jurisprudence conflictuelle)
Progression pedagogique : 1. Section 4.1.1 : Sémantiques fondamentales (Grounded, Preferred, Stable) 2. Section 4.1.2 : Extension CF2 pour cycles impairs 3. Section 4.1.3 : Generation aleatoire pour tests et benchmarks 4. Section 4.1.4 : Apprentissage de frameworks (concept avance)
4.1.1 Sémantiques de Dung : Fondements
Les cadres d’argumentation abstraits (Dung, 1995) sont définis par :
Origine. Les cadres d’argumentation abstraits (AAF) et leurs sémantiques (grounded, preferred, stable, complete) sont introduits par Dung, P. M. (1995), On the acceptability of arguments and its fundamental rôle in nonmonotonic reasoning, logic programming and n-person games, Artificial Intelligence 77(2):321-357 — le papier fondateur de l’argumentation computationnelle moderne, d’ou derivent les quatre sémantiques comparees ci-dessous. - Un ensemble d’arguments (noeuds) - Une relation d’attaque (arcs dirigés)
Les différentes sémantiques déterminent quels ensembles d’arguments sont “acceptables” :
Le moteur derrière les sémantiques : fonction caractéristique et lemme fondamental
Le tableau ci-dessus présente « Complete = Fixpoint » et « Grounded = unique » comme des propriétés. Ces propriétés ne sont pas magiques : elles découlent d’un opérateur que Dung (1995) définit explicitement.
Fonction caractéristique F. Pour un cadre d’argumentation AF, on définit l’opérateur
F(S) = { a ∈ AF | a est acceptable vis-à-vis de S }
où « a est acceptable vis-à-vis de S » signifie : tout attaquant de a est attaqué par au moins un argument de S (S « défend » a). Intuitivement, F(S) est l’ensemble des arguments que S est capable de protéger.
Complete = point fixe de F : une extension complete est exactement un ensemble E tel que F(E) = E (il contient tous les arguments qu’il défend, rien de plus). C’est ce que la ligne du tableau appelle « Fixpoint ».
Grounded = plus petit point fixe : l’extension grounded est le plus petit point fixe de F. On l’obtient en itérant F depuis l’ensemble vide : F(∅) ⊆ F(F(∅)) ⊆ ... jusqu’à converger. Le résultat est unique (c’est le plus petit), d’où getModel() (singulier) pour le SimpleGroundedReasoner plutôt que getModels().
Illustration sur AF1 (a1 <-> b1 -> c1). Partons de S = ∅ : - F(∅) = arguments non attaqués du tout = ∅ (chacun de a1, b1, c1 est attaqué : a1 par b1, b1 par a1, c1 par b1). - On est déjà en point fixe : F(∅) = ∅. L’extension grounded vaut donc {} — c’est exactement ce que renvoie SimpleGroundedReasoner().getModel(af1) dans la cellule suivante. Le conflit symétrique a1 <-> b1 laisse le raisonneur sceptique incapable de trancher.
Lemme fondamental de Dung (monotonie de l’admissibilité). Si S est admissible et a est acceptable vis-à-vis de S, alors S ∪ {a} reste admissible. En clair : on peut toujours étendre une position admissible en acceptant un argument qu’elle défend, sans jamais perdre la propriété d’admissibilité. Ce lemme est le moteur qui garantit : - l’existence d’extensions preferred (on peut grandir tant qu’on reste admissible, jusqu’à un maximal), - la convergence de l’itération de F vers le grounded.
C’est aussi ce qui explique pourquoi, dans la sortie de la cellule suivante, {a1} figure parmi les extensions admissibles d’AF1 : a1 se défend lui-même contre b1 (puisque a1 attaque b1), donc accepter a1 seul est une position défendable — même si elle n’est ni complete (elle ne contient pas tout ce qu’elle défend) ni maximale.
Exemples concrets pour comprendre les sémantiques
Nous allons maintenant illustrer ces concepts avec deux frameworks classiques :
Exemple 1 : Conflit symetrique
a1 <-> b1 -> c1
a1 et b1 s’attaquent mutuellement (conflit symetrique)
b1 attaque aussi c1 (attaque unilaterale)
Question : Peut-on accepter a1 ET b1 simultanement ? Non (conflit)
Intuition : Il faut choisir un “camp” (a1+c1 OU b1)
Exemple 2 : Cycle impair
a -> b -> c -> a
Cycle de longueur 3 (impair)
Chaque argument attaque le suivant
Question : Existe-t-il une extension stable ? Non (cycles impairs cassent Stable)
Intuition : Aucune position coherente n’est possible (paradoxe du menteur)
Méthode de calcul : 1. Créer le framework avec DungTheory() 2. Ajouter arguments avec Argument("nom") 3. Ajouter attaques avec Attack(source, cible) 4. Utiliser les raisonneurs : SimpleGroundedReasoner(), SimpleStableReasoner(), etc. 5. Appeler getModel() (extension unique) ou getModels() (collection)
# --- 4.1.1 Cadres d'Argumentation Abstraits (Dung) : Bases et Sémantiques ---print("\n--- 4.1.1 Cadres d'Argumentation Abstraits (Dung) : Bases et Sémantiques ---")# Vérifier si la JVM est prêteifnot jvm_ready:print("❌ ERREUR: JVM non démarrée. Impossible de continuer cet exemple.")else:print("ℹ️ JVM prête. Exécution de l'exemple Dung...")try:# Imports nécessaires pour Dungimport jpypefrom jpype.types import*from org.tweetyproject.arg.dung.syntax import DungTheory, Argument, Attack# Importer plusieurs raisonneursfrom org.tweetyproject.arg.dung.reasoner import ( SimpleGroundedReasoner, SimpleStableReasoner, SimplePreferredReasoner, SimpleCompleteReasoner, SimpleAdmissibleReasoner, SimpleConflictFreeReasoner )# Importer Semantics si besoin pour certains raisonneurs plus avancés (non utilisés ici)# from org.tweetyproject.arg.dung.semantics import Semanticsfrom java.util import Collection # Pour vérifier taille retourprint("✔️ Imports Dung réussis.")# --- Exemple 1: A <-> B -> C --- af1 = DungTheory() a1 = Argument("a1"); b1 = Argument("b1"); c1 = Argument("c1")# Ajouter des arguments af1.add(a1); af1.add(b1); af1.add(c1)# Ajouter des attaques af1.add(Attack(a1, b1)); af1.add(Attack(b1, a1)); af1.add(Attack(b1, c1))print("\n--- AF1: a1 <-> b1 -> c1 ---")print("Cadre :", af1)# Calculer les extensions pour différentes sémantiquesprint("\nCalcul des extensions pour AF1:")try:# Grounded: getModel() retourne une Extension, getModels() retourne une Collection<Extension> grounded_ext = SimpleGroundedReasoner().getModel(af1) # Plus direct pour groundedprint(f" - Grounded : {{{grounded_ext}}}") # Afficher comme un ensemble pour la cohérenceexceptExceptionas e: print(f" Erreur Grounded: {e}")try: stable_exts = SimpleStableReasoner().getModels(af1)print(f" - Stable ({stable_exts.size()}):", stable_exts)exceptExceptionas e: print(f" Erreur Stable: {e}")try: preferred_exts = SimplePreferredReasoner().getModels(af1)print(f" - Preferred ({preferred_exts.size()}):", preferred_exts)exceptExceptionas e: print(f" Erreur Preferred: {e}")try: complete_exts = SimpleCompleteReasoner().getModels(af1)print(f" - Complete ({complete_exts.size()}):", complete_exts)exceptExceptionas e: print(f" Erreur Complete: {e}")try: admissible_exts = SimpleAdmissibleReasoner().getModels(af1)# Convertir la Collection Java en liste Python pour len()# Note: Cela peut être coûteux si la collection est énorme admissible_list =list(admissible_exts)print(f" - Admissible ({len(admissible_list)}):", admissible_exts) # Afficher la collection JavaexceptExceptionas e: print(f" Erreur Admissible: {e}")try: conflict_free_exts = SimpleConflictFreeReasoner().getModels(af1) cf_list =list(conflict_free_exts)print(f" - ConflictFree ({len(cf_list)}):", conflict_free_exts) # Attention, peut être très grandexceptExceptionas e: print(f" Erreur ConflictFree: {e}")# --- Exemple 2: Cycle a->b->c->a --- af_cycle = DungTheory() a_cy = Argument("a_cy"); b_cy = Argument("b_cy"); c_cy = Argument("c_cy") af_cycle.add(a_cy); af_cycle.add(b_cy); af_cycle.add(c_cy) af_cycle.add(Attack(a_cy, b_cy)); af_cycle.add(Attack(b_cy, c_cy)); af_cycle.add(Attack(c_cy, a_cy))print("\n--- AF Cycle: a -> b -> c -> a ---")print("Cadre :", af_cycle)print("\nCalcul des extensions pour AF Cycle:")try:print(" - Grounded :", SimpleGroundedReasoner().getModel(af_cycle)) # {}exceptExceptionas e: print(f" Erreur Grounded: {e}")try: stable_exts_cy = SimpleStableReasoner().getModels(af_cycle)print(f" - Stable ({stable_exts_cy.size()}):", stable_exts_cy) # {}exceptExceptionas e: print(f" Erreur Stable: {e}")try: preferred_exts_cy = SimplePreferredReasoner().getModels(af_cycle)print(f" - Preferred ({preferred_exts_cy.size()}):", preferred_exts_cy) # [{}]exceptExceptionas e: print(f" Erreur Preferred: {e}")try: complete_exts_cy = SimpleCompleteReasoner().getModels(af_cycle)print(f" - Complete ({complete_exts_cy.size()}):", complete_exts_cy) # [{}]exceptExceptionas e: print(f" Erreur Complete: {e}")exceptImportErroras e:print(f"❌ Erreur d'import pour l'Argumentation Abstraite : {e}")print(" Vérifiez le JAR 'org.tweetyproject.arg.dung'.")except jpype.JException as e_java:print(f"❌ Erreur Java générale dans l'exemple Dung: {e_java.message()}")# print(e_java.stacktrace()) # Décommenter pour trace Java complèteexceptExceptionas e_gen:print(f"❌ Erreur Python inattendue dans l'exemple Dung: {e_gen}")import traceback traceback.print_exc()
Lecons cles : 1. Les cycles impairs cassent la sémantique stable -> utiliser CF2 (section suivante) 2. Grounded est la position la plus prudente (sceptique) 3. Preferred/Stable donnent les positions credules (choisir un camp)
Une vue équivalente : le labeling à trois valeurs (in / out / undec)
Origine. La présentation des sémantiques par labellings trivalués (in / out / undec) — équivalente aux extensions de Dung mais plus opérationnelle — est développée par Caminada, M. (2006), On the issue of reinstatement in argumentation, JELIA, pp. 111-123, et systématisée par Modgil, S. & Caminada, M. (2009), Proof théories and algorithms for abstract argumentation frameworks, in Argumentation in Artificial Intelligence, Springer, pp. 105-129.
Il existe une seconde façon, strictement équivalente, de présenter les sémantiques : au lieu de raisonner sur des ensembles d’arguments acceptés (les extensions), on étiquette chaque argument par l’une de trois valeurs :
Label
Définition
Rôle
in
l’argument est accepté
membre de l’extension
out
l’argument est rejeté
attaqué par au moins un argument in
undec
indéterminé
ni in ni out (boucle, cycle, conflit non tranché)
Un labeling est légal quand : tout in n’est attaqué que par des out, et tout out est attaqué par au moins un in. La correspondance avec les extensions est exacte :
un labeling complete ↔︎ une extension complete (les in forment l’extension),
le labeling grounded ↔︎ l’extension grounded,
les labelings preferred ↔︎ les extensions preferred.
Sur AF1 (a1 <-> b1 -> c1), le labeling grounded (associé à l’extension {}) attribue undec aux trois arguments : a1 et b1 s’attaquent mutuellement sans qu’aucun ne soit défendu (ni in ni out), et c1 n’est défendu par personne. C’est la traduction labellisée du Grounded = {} observé dans la sortie. À l’inverse, le labeling preferred{a1, c1} met a1 et c1in, b1out — et le labeling {b1} fait l’inverse : deux visions du monde, deux labelings.
Pourquoi ce point de vue compte ici. La section 4.1.4 « Apprentissage de cadres » (plus bas) reconstruit un AF à partir de labellisations partielles (IN, OUT, UNDEC) fournies par un oracle : c’est précisément ce vocabulaire à trois valeurs. Le voir défini ici, sur la théorie de Dung, permet de comprendre l’apprentissage non comme une notion ad hoc mais comme la manipulation directe des labelings que toute sémantique produit. Dans la pratique, Tweety expose ces labelings via la classe Labeling (paquet org.tweetyproject.arg.dung.semantics), en miroir des Simple*Reasoner utilisés ci-dessus.
Problematique des Cycles Impairs
Les résultats ci-dessus revelent une limitation fondamentale de la sémantique Stable :
Observation critique : - Le cycle a -> b -> c -> a (longueur 3 = impair) n’a aucune extension stable - La sémantique Preferred retourne uniquement l’extension vide {} - Aucun argument n’est accepte sceptiquement (Grounded = {})
Pourquoi ce problème ?
Un cycle impair créé un paradoxe logique : 1. Si a est IN, alors b doit etre OUT (attaque par a) 2. Si b est OUT, alors c doit etre IN (non attaque) 3. Si c est IN, alors a doit etre OUT (attaque par c) 4. Contradiction : a doit etre IN ET OUT simultanement
Analogie philosophique : Le paradoxe du menteur - “Cette phrase est fausse” - Si vraie -> fausse, si fausse -> vraie (cycle infini)
Solution : La sémantique CF2 (prochaine section) resout ce problème en decomposant le graphe en composantes fortement connexes (SCCs) et en traitant les cycles de facon récursive.
Impact pratique : - Les debats reels contiennent souvent des cycles (A attaque B, B attaque C, C attaque A) - La sémantique Stable echoue sur ~30% des frameworks aleatoires (selon la densite) - CF2 garantit toujours au moins une extension
4.1.2 Sémantique CF2 : Gestion des Cycles
La sémantique CF2 (Baroni et al., 2005) est conçue pour traiter les cadres avec cycles impairs.
Problème des cycles impairs : - Un cycle a→b→c→a n’a pas d’extension stable - La sémantique stable échoue sur ces structures
Solution CF2 : 1. Décomposition en SCCs (Strongly Connected Components) 2. Traitement récursif des composantes 3. Propagation des choix entre composantes
Avantage : CF2 garantit toujours au moins une extension, même sur les cadres “pathologiques”.
API Tweety : SccCF2Reasoner implémente cette sémantique.
# --- 4.1.2 Sémantique CF2 ---print("\n--- 4.1.2 Sémantique CF2 ---")# Vérifier si la JVM est prêteifnot jvm_ready:print("❌ ERREUR: JVM non démarrée. Impossible de continuer cet exemple.")else:print("ℹ️ JVM prête. Exécution de l'exemple CF2...")try:# Imports (peuvent être déjà faits, mais sécurité)import jpypefrom jpype.types import*from org.tweetyproject.arg.dung.syntax import DungTheory, Argument, Attackfrom org.tweetyproject.arg.dung.reasoner import SccCF2Reasonerfrom org.tweetyproject.arg.dung.semantics import Extension # Pour type hinting éventuelfrom java.util import Collectionprint("✔️ Imports Dung (pour CF2) réussis.")# --- Exemple AF2 : Cycle a->b->c->d->e->a, e->f ---# (Recréation pour autonomie de la cellule) af2 = DungTheory() args_cf2_map = {name: Argument(name) for name in"abcdef"} # Utiliser un dictionnairefor arg in args_cf2_map.values(): af2.add(arg) attacks_cf2 = [("a","b"), ("b","c"), ("c","d"), ("d","e"), ("e","a"), ("e","f")]for s, t in attacks_cf2:# S'assurer que les arguments existent avant d'ajouter l'attaqueif s in args_cf2_map and t in args_cf2_map: af2.add(Attack(args_cf2_map[s], args_cf2_map[t]))else:print(f"WARN: Argument(s) non trouvé(s) pour l'attaque ({s},{t})")print("\n--- AF pour CF2 : Cycle a->b->c->d->e->a, e->f ---")print("Cadre :", af2)# --- Raisonnement CF2 --- cf2_reasoner = SccCF2Reasoner()print("\nCalcul des extensions CF2:")try: cf2_extensions_collection = cf2_reasoner.getModels(af2) # Retourne Collection<Extension>if cf2_extensions_collection.isEmpty():print(" (Aucune extension CF2 trouvée)")else:# Itérer sur la collection Java ext_iterator = cf2_extensions_collection.iterator() count =0while ext_iterator.hasNext(): ext = ext_iterator.next()# Pour un affichage plus propre des arguments dans l'extension: args_in_ext =", ".join(sorted([str(arg.getName()) for arg in ext]))print(f" - {{{args_in_ext}}}") count +=1print(f" ({count} extension(s) trouvée(s))")except jpype.JException as e_cf2_java:print(f" ❌ Erreur Java lors du raisonnement CF2: {e_cf2_java.message()}")# print(e_cf2_java.stacktrace())exceptExceptionas e_cf2_py:print(f" ❌ Erreur Python lors du raisonnement CF2: {e_cf2_py}")# Gestion globaleexceptImportErroras e:print(f"❌ Erreur d'import pour CF2 : {e}. Vérifiez le JAR 'arg.dung'.")except jpype.JException as e_java:print(f"❌ Erreur Java générale dans l'exemple CF2: {e_java.message()}")exceptExceptionas e_gen:print(f"❌ Erreur Python inattendue dans l'exemple CF2: {e_gen}")import traceback traceback.print_exc()
--- 4.1.2 Sémantique CF2 ---
ℹ️ JVM prête. Exécution de l'exemple CF2...
✔️ Imports Dung (pour CF2) réussis.
--- AF pour CF2 : Cycle a->b->c->d->e->a, e->f ---
Cadre : <{ a, b, c, d, e, f },[(b,c), (d,e), (e,a), (a,b), (c,d), (e,f)]>
Calcul des extensions CF2:
- {b, e}
- {c, e}
- {a, c, f}
- {a, d, f}
- {b, d, f}
(5 extension(s) trouvée(s))
Interpretation des extensions CF2
La sémantique CF2 resout le problème des cycles impairs en decomposant le graphe :
Structure du framework : - Cycle principal : a -> b -> c -> d -> e -> a (cycle de longueur 5 = impair) - Attaque supplementaire : e -> f
Les 5 extensions trouvees :
Extension
Arguments IN
Interpretation
{b, e}
2 args non adjacents dans le cycle
Un “camp” valide
{c, e}
2 args non adjacents
Autre camp valide
{a, c, f}
a et c + f (protege par e absent)
Camp avec f
{a, d, f}
a et d + f
Autre combinaison
{b, d, f}
b et d + f
Dernière combinaison
Pourquoi 5 extensions ? - Dans un cycle de 5, on peut choisir 2 arguments non adjacents de 5 facons - Certaines extensions incluent f (quand son attaquant e est OUT)
Avantage de CF2 : - Garantit toujours au moins une extension (contrairement a Stable) - Traite les cycles de facon coherente via decomposition SCC - Utile pour les debats circulaires ou les préférences cycliques
Transition vers l’experimentation
Nous avons maintenant explore les sémantiques fondamentales et leurs extensions (CF2). La prochaine étape consiste a experimenter a grande echelle :
Questions de recherche : 1. Quelle proportion de frameworks aleatoires possede des extensions stables ? 2. Comment la densite d’attaques influence-t-elle le nombre d’extensions ? 3. Les frameworks symetriques ont-ils des proprietes particulieres ?
Approche experimentale : - Generer des frameworks aleatoires avec paramètres contrôles - Calculer les extensions pour différentes sémantiques - Analyser les statistiques (taille moyenne, nombre d’extensions, etc.)
La section suivante introduit la generation automatique de frameworks pour faciliter ces experimentations.
4.1.3 Génération de Cadres Aléatoires
Tweety permet de générer des cadres d’argumentation pour : - Tests de performance des raisonneurs - Études statistiques des sémantiques - Benchmarks pour comparer algorithmes
Paramètres de génération : - numberOfArguments : Nombre d’arguments à créer - attackProbability : Probabilité d’attaque entre deux arguments (modèle Erdős-Rényi)
Le générateur aleatoire a produit un cadre avec 6 arguments et 9 attaques (probabilite 0.25). Note : cette génération étant aléatoire (générateur non semé), une ré-exécution produit un cadre différent ; les valeurs ci-dessous décrivent la sortie committée de cette cellule.
Cette generation aleatoire permet de : 1. Tester les raisonneurs sur des structures variees 2. Etudier statistiquement les sémantiques (combien de frameworks ont des extensions stables ?) 3. Generer des benchmarks pour comparer performances d’algorithmes
Exercice suggere : Calculer les extensions Preferred et Stable du framework genere ci-dessus. Y a-t-il des cycles impairs ? Si oui, la sémantique Stable retourne-t-elle des extensions vides ?
4.1.4 Apprentissage de Cadres (Bug Connu)
⚠️ Cette section est documentée mais non exécutable en raison d’un bug interne de Tweety (constaté en 1.28, toujours présent en 1.30) : ClassCastException: Tautology cannot be cast to AssociativePlFormula.
Concept pédagogique :
L’apprentissage de cadres vise à reconstruire un AF à partir de labellisations partielles (IN, OUT, UNDEC) fournies par un oracle.
Cas d’usage : - Élicitation de préférences : Déduire les relations d’attaque depuis des jugements humains - Ingénierie de connaissances : Construire des bases argumentatives depuis des exemples
# --- 4.1.4 Apprentissage de Cadres Dung (depuis Labellisations) ---print("\n--- 4.1.4 Apprentissage de Cadres Dung ---")print("!! SECTION COMMENTÉE !!")print("L'exécution de cet exemple échoue en raison d'une ClassCastException interne à Tweety")print("(Tautology cannot be cast to AssociativePlFormula) lors de l'appel à getLabeling/learnLabeling")print("pour le cadre d'argumentation spécifique utilisé ici. Ceci semble être un bug interne.")# if not jvm_ready:# print("❌ ERREUR: JVM non démarrée.")# else:# print("ℹ️ JVM prête. Exécution de l'exemple d'apprentissage...")# try:# # Imports# import jpype# from jpype.types import *# from org.tweetyproject.arg.dung.syntax import DungTheory, Argument, Attack# from org.tweetyproject.arg.dung.learning import SimpleAFLearner# from org.tweetyproject.arg.dung.learning.syntax import Entity# from org.tweetyproject.arg.dung.semantics import Semantics# # Import de Label retiré (correction précédente)## print("✔️ Imports pour apprentissage Dung réussis.")## # 1. Définir le cadre "caché"# hidden_af = DungTheory()# a_learn = Argument("a"); b_learn = Argument("b"); c_learn = Argument("c")# hidden_af.add(a_learn); hidden_af.add(b_learn); hidden_af.add(c_learn)# hidden_af.add(Attack(a_learn, b_learn)); hidden_af.add(Attack(b_learn, a_learn)); hidden_af.add(Attack(b_learn, c_learn))# print("\nCadre caché (à apprendre):", hidden_af)## # 2. Créer l'Oracle# oracle = Entity(hidden_af)# arguments_known = oracle.getArguments()# print("Arguments connus par l'apprenant:", arguments_known)## # 3. Créer l'Apprenant# learner = SimpleAFLearner(arguments_known)# print(f"État initial apprenant: {learner.getNumberOfFrameworks()} cadres compatibles possibles.")## # 4. Apprendre depuis des labellisations# # Labellisation Stable# print("\nApprentissage depuis labellisation Stable:")# try:# labeling_stable = oracle.getLabeling(Semantics.STABLE_SEMANTICS) # C'est ici que l'erreur se produit# print(f" Oracle fournit Labellisation STABLE: {labeling_stable}")# learner.learnLabeling(labeling_stable)# print(f" Après STABLE: {learner.getNumberOfFrameworks()} cadres compatibles restants.")# except jpype.JException as e_stable:# print(f" Erreur lors de l'obtention/apprentissage de la labellisation Stable: {e_stable.message()}")# # Afficher la stacktrace Java peut aider à confirmer l'erreur interne# # print(e_stable.stacktrace())## # Labellisation Conflict-Free (pourrait aussi échouer)# print("\nApprentissage depuis labellisation Conflict-Free:")# try:# labeling_cf = oracle.getLabeling(Semantics.CONFLICTFREE_SEMANTICS)# print(f" Oracle fournit Labellisation CONFLICT_FREE: {labeling_cf}")# learner.learnLabeling(labeling_cf)# print(f" Après CONFLICT_FREE: {learner.getNumberOfFrameworks()} cadres compatibles restants.")# except jpype.JException as e_cf:# print(f" Erreur lors de l'obtention/apprentissage de la labellisation ConflictFree: {e_cf.message()}")### # 5. Obtenir le(s) cadre(s) appris# # Ce code ne sera probablement pas atteint# learned_af = learner.getModel()# print("\nCadre appris (un des cadres compatibles) :")# print(str(learned_af))## # ... (Blocs except ImportError, JException, Exception comme avant) ...# except ImportError as e:# print(f"❌ Erreur d'import pour l'apprentissage Dung : {e}.")# except jpype.JException as e_java:# print(f"❌ Erreur Java générale dans l'exemple apprentissage Dung: {e_java.message()}")# except Exception as e_gen:# print(f"❌ Erreur Python inattendue dans l'exemple apprentissage Dung: {e_gen}")# import traceback# traceback.print_exc()
--- 4.1.4 Apprentissage de Cadres Dung ---
!! SECTION COMMENTÉE !!
L'exécution de cet exemple échoue en raison d'une ClassCastException interne à Tweety
(Tautology cannot be cast to AssociativePlFormula) lors de l'appel à getLabeling/learnLabeling
pour le cadre d'argumentation spécifique utilisé ici. Ceci semble être un bug interne.
4.2 Equivalence de Frameworks d’Argumentation (Nouveaute v1.30)
Tweety v1.30 introduit le module org.tweetyproject.arg.dung.equivalence qui permet de comparer deux cadres d’argumentation selon différentes notions d’equivalence.
Pourquoi comparer des AFs ? - Deux experts peuvent modeliser un même debat avec des AFs syntaxiquement différents mais semantiquement equivalents - Simplification d’un AF sans perdre son pouvoir argumentatif - Detection de reformulations ou de redundances dans des bases argumentatives
9 notions d’equivalence (de la plus forte a la plus faible) :
Notion
Principe
Constructeur
Syntactic
Même arguments et attaques (isomorphisme)
SyntacticEquivalence()
Strong
Equivalents sous toute expansion
StrongEquivalence(Semantics.X)
Standard
Même extensions sous X-sémantique
StandardEquivalence(Semantics.X)
Strong Expansion
Equivalence sous expansions fortes
StrongExpansionEquivalence(Semantics.X)
Normal Expansion
Equivalence sous expansions normales
NormalExpansionEquivalence(Semantics.X)
Weak Expansion
Equivalence sous expansions faibles
WeakExpansionEquivalence(Semantics.X)
Normal Deletion
Equivalence sous suppressions
NormalDeletionEquivalence(Semantics.X)
Local Expansion
Equivalence sous expansions locales
LocalExpansionEquivalence(Semantics.X)
Serialisation
Equivalence de serialisations
SerialisationEquivalence(Semantics.X)
Concept cle :StrongEquivalence(CO) signifie que deux AFs auront toujours les mêmes extensions completes, quel que soit le contexte additionnel (nouveaux arguments/attaques ajoutes). C’est la notion la plus robuste.
API Tweety :
eq = StrongEquivalence(Semantics.CO) # ou PR, ST, GR...result = eq.isEquivalent(af1, af2) # True ou False
AF1 vs AF3 (copie identique) : Toutes les notions retournent True car les deux AFs ont exactement les mêmes arguments et attaques.
AF1 vs AF2 (structure inversee) : Les résultats différent selon la notion : - Syntactic : False car les arcs sont différents (a->b vs b->a) - Strong : False car sous certaines expansions, les comportements divergent - Standard : Dependent de la sémantique choisie (CO, PR, ST, GR)
Lecon cle : L’equivalence syntaxique est la plus stricte (isomorphisme exact), tandis que les equivalences sémantiques (Standard, Expansion) tolerent des différences structurelles si les extensions coincident.
Application pratique : - Verifier qu’une simplification d’AF preserve la sémantique - Detecter des redundances dans des bases argumentatives - Comparer des modelisations de différents experts
4.3 Explications en Argumentation (Nouveaute v1.30)
Le module org.tweetyproject.arg.explanations (v1.30) permet de generer des explications sur l’acceptation ou le rejet d’un argument dans un AF.
Deux types d’explications :
Type
Question answered
Classe Tweety
Suffisante
Quels arguments suffisent a expliquer l’acceptation de X ?
SufficientExplanationReasoner
Séquentielle
Quelle chaîne dialectique justifie X ?
DialecticalSequenceExplanationReasoner
Explication suffisante : - Un argument a est pertinent pour expliquer c si a fait partie d’une explication suffisante de l’acceptation de c - Méthode : isRelevantFor(theory, source, target)
Explication séquentielle : - Produit une chaîne dialectique justifiant l’acceptation d’un argument - a -> b -> c peut etre une sequence expliquant pourquoi c est accepte (a attaque b qui attaquait c) - Méthode : getExplanations(theory, target_argument)
# --- 4.3 Explications en Argumentation (v1.30) ---print("\n--- 4.3 Explications en Argumentation (v1.30) ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:try:from org.tweetyproject.arg.dung.syntax import DungTheory, Argumentfrom org.tweetyproject.arg.explanations.reasoner.acceptance import ( SufficientExplanationReasoner, DialecticalSequenceExplanationReasoner )# --- Construire un AF avec plusieurs niveaux d'attaque ---# a -> b -> c# b -> d -> e# f -> c theory = DungTheory() args = {n: Argument(n) for n in"abcdef"}for arg in args.values(): theory.add(arg) attacks = [("a", "b"), ("b", "c"), ("b", "d"), ("d", "e"), ("f", "c")]for src, tgt in attacks: theory.addAttack(args[src], args[tgt])print(f"Framework: {theory}")# --- 1. Explications suffisantes ---print("\n--- Explications Suffisantes ---") suf = SufficientExplanationReasoner() pairs = [("a", "c"), ("a", "e"), ("b", "c"), ("f", "e"), ("d", "c")]for src, tgt in pairs: relevant = suf.isRelevantFor(theory, args[src], args[tgt])print(f" {src} pertinent pour expliquer {tgt} ? {relevant}")# --- 2. Explications sequentielles (dialectiques) ---print("\n--- Explications Sequentielles (Dialectiques) ---") dialectical = DialecticalSequenceExplanationReasoner() target_args = ["c", "e", "a"]for tgt in target_args: explanations = dialectical.getExplanations(theory, args[tgt])print(f" Explications pour '{tgt}': {explanations}")if explanations and explanations.size() >0: it = explanations.iterator()while it.hasNext(): expl = it.next()print(f" -> {expl}")exceptImportErroras e:print(f"Erreur d'import (explications): {e}")exceptExceptionas e:print(f"Erreur: {e}")import traceback traceback.print_exc()
--- 4.3 Explications en Argumentation (v1.30) ---
Framework: <{ a, b, c, d, e, f },[(b,c), (d,e), (b,d), (a,b), (f,c)]>
--- Explications Suffisantes ---
a pertinent pour expliquer c ? True
a pertinent pour expliquer e ? True
b pertinent pour expliquer c ? True
f pertinent pour expliquer e ? False
d pertinent pour expliquer c ? False
--- Explications Sequentielles (Dialectiques) ---
Explications pour 'c': []
Explications pour 'e': []
Explications pour 'a': [[{a}, []]]
-> [{a}, []]
Interpretation des explications
Explications suffisantes : - a est pertinent pour expliquer c car a attaque b qui attaquait c (defense indirecte) - a est aussi pertinent pour expliquer e : la chaîne a -> b -> d -> e (3 sauts) fait de a un contributeur indirect a l’explication de e - b est pertinent pour expliquer c car b attaque directement c
Explications non pertinentes : - f n’est pas pertinent pour expliquer e (aucun chemin causale de f vers e) - d n’est pas pertinent pour expliquer c (d est sur la branche b -> d -> e, pas sur le chemin vers c)
Explications séquentielles : - Chaque explication est une chaîne dialectique montrant comment les attaques et contre-attaques justifient l’argument cible - Permet de tracer le raisonnement pas-a-pas (auditabilite)
Contraste avec les sémantiques classiques : - Les sémantiques (Grounded, Preferred) repondent “quels arguments sont acceptes ?” - Les explications repondent “pourquoi cet argument est-il accepte ?” (question d’intelligibilite)
Applications : - Interface explicative pour systèmes d’aide a la decision - Audit de decisions automatisees (XAI - Explainable AI) - Pedagogie : comprendre le raisonnement d’un système argumentatif
4.4 Raisonnement Causal par Argumentation (Nouveaute v1.30)
Le module org.tweetyproject.causal (v1.30) implemente le raisonnement causal via l’argumentation. Il permet de modeliser des relations causales et de repondre a des requêtes observationnelles, interventionnelles et contrefactuelles.
API en 4 étapes : 1. Construire le modèle causal : atomes de fond + atomes explicables avec equations 2. Encapsuler dans une base de connaissances avec des hypotheses 3. Définir les observations (faits constates) 4. Requeter : le raisonneur induit un AF (DungTheory) et repond
Lien avec l’argumentation : Le raisonneur transforme le problème causal en un AF de Dung ou chaque argument represente une explication causale possible, et les attaques captent les incompatibilites entre explications.
Formules logiques : Les equations structurelles utilisent Conjunction, Disjunction, et Negation du module logics.pl.
# --- 4.4 Raisonnement Causal par Argumentation (v1.30) ---print("\n--- 4.4 Raisonnement Causal par Argumentation (v1.30) ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:try:from org.tweetyproject.logics.pl.syntax import Proposition, Negation, Conjunction, Disjunctionfrom org.tweetyproject.causal.syntax import StructuralCausalModel, CausalKnowledgeBasefrom org.tweetyproject.causal.reasoner import ArgumentationBasedCausalReasonerfrom java.util import HashSet# --- Scenario medical : diagnostics causaux ---# Variables exogenes (causes initiales) corona = Proposition("corona") influenza = Proposition("influenza") at_risk = Proposition("at-risk")# Variables explicables (effets intermediaires et finaux) covid = Proposition("covid") flu = Proposition("flu") fever = Proposition("fever") chills = Proposition("chills") short_breath = Proposition("short-of-breath")# 1. Construire le modele causal model = StructuralCausalModel() model.addBackgroundAtom(corona) model.addBackgroundAtom(influenza) model.addBackgroundAtom(at_risk)# Equations structurelles : X = f(parents)# Note jpype : Disjunction/Conjunction a deux constructeurs surcharges# (PlFormula, PlFormula) et (PlFormula[]) -> on construit via add()# pour lever l'ambiguite de resolution d'overload. model.addExplainableAtom(covid, corona) model.addExplainableAtom(flu, influenza) fever_eq = Disjunction() fever_eq.add(covid) fever_eq.add(flu) model.addExplainableAtom(fever, fever_eq) model.addExplainableAtom(chills, fever) short_breath_eq = Conjunction() short_breath_eq.add(covid) short_breath_eq.add(at_risk) model.addExplainableAtom(short_breath, short_breath_eq)print(f"Modele causal construit : {model.getExplainableAtoms().size()} atomes explicables")# 2. Base de connaissances + hypotheses cbase = CausalKnowledgeBase(model) cbase.addAssumption(Negation(corona)) # Hypothese : pas de corona cbase.addAssumption(Negation(influenza)) # Hypothese : pas d'influenza cbase.addAssumption(at_risk) # Hypothese : patient a risqueprint(f"Hypotheses : {cbase.getAssumptions().size()}")# 3. Observations observations = HashSet() observations.add(fever) # Le patient a de la fievreprint(f"Observation : fievre")# 4. Raisonnement reasoner = ArgumentationBasedCausalReasoner()# 4a. AF induit (vue argumentative) induced_af = reasoner.getInducedTheory(cbase, observations)print(f"\nAF induit : {induced_af.getNodes().size()} arguments, "f"{induced_af.getAttacks().size()} attaques")# 4b. Requetes causales queries = [(short_breath, "essoufflement"), (chills, "frissons"), (covid, "covid"), (flu, "grippe")]print("\nResultats des requetes causales :")for prop, label in queries: result = reasoner.query(cbase, observations, prop)print(f" {label} ? {result}")# 4c. Toutes les conclusions derivables conclusions = reasoner.getConclusions(cbase, observations)print(f"\nConclusions derivables ({conclusions.size()}) :") it = conclusions.iterator()while it.hasNext():print(f" {it.next()}")exceptImportErroras e:print(f"Erreur d'import (causal): {e}")exceptExceptionas e:print(f"Erreur: {e}")import traceback traceback.print_exc()
Le modèle causal encode des relations medicales : - Causes endogenes (corona, influenza) : variables de fond qui declenchent les effets - Effets explicables (covid, flu, fever, chills, short_breath) : consequence directe ou indirecte
Le CausalKnowledgeBase combine le modèle structurel avec des hypotheses (negations des causes, facteurs de risque). Les observations (ex: fever) declenchent un raisonnement argumentatif :
Théorie induite : L’AF genere reflete les conflits entre explications causales possibles
Requête : Pour chaque proposition, le raisonneur determine si elle est croyable (TRUE), sa negation est croyable (FALSE), ou indetermine (UNDECIDED)
Conclusions : L’ensemble des conclusions acceptees revele quelles explications causales sont soutenues par les observations
Cette approche montre comment l’argumentation abstraite de Dung peut etre appliquee au raisonnement causal, une avancee majeure de Tweety v1.30.
Synthèse intermédiaire : de Dung aux nouveautés v1.30
Ce notebook a couvert les cadres d’argumentation abstraits de Dung (1995) et les nouveautes Tweety v1.30 :
Section
Concepts cles
4.1.1 Bases
Arguments, attaques, DungTheory, 6 sémantiques
4.1.2 CF2
Decomposition SCC, gestion des cycles impairs
4.1.2bis Reparation du vide stable
Semi-stable (Caminada 2006), ideal (Dung-Mancarella-Toni 2007) vs CF2
Explications suffisantes et séquentielles (dialectiques)
4.4 Raisonnement Causal (v1.30)
Modèles causaux structurels, bases de connaissances causales, AF induits
Hiérarchie des sémantiques :
ConflictFree -> Admissible -> Complete -> Grounded (unique, sceptique)
-> Preferred (maximale, credule)
-> Stable (attaque tout, pas toujours existant)
-> SemiStable (maximise S u S+, existe toujours)
-> Ideal (unique, incluse dans tous les preferred)
Points cles a retenir : - Grounded : Extension unique, position sceptique (la plus prudente) - Preferred : Extensions maximales, positions credules (peut y en avoir plusieurs) - Stable : N’existe pas toujours (cycles impairs). Deux reparations mesurees : semi-stable / ideal (conservatrices, existent toujours, mais triviales sur le cycle impair) et CF2 (informative, mais quitte l’admissibilite) - Equivalence : Plusieurs notions pour comparer des AFs (syntaxique vs sémantique) - Explications : Comprendre “pourquoi” un argument est accepte (XAI) - Causal : L’argumentation appliquee au raisonnement causal (diagnostics, interventions)
Transition : vers l’argumentation structurée
Le notebook suivant explore l’argumentation structuree avec ASPIC+, DeLP, ABA et ASP.
Les exemples ci-dessous illustrent les concepts avances de l’argumentation abstraite. Completer ensuite les exercices proposes.
Notre implémentation
Pour chaque exercice, nous construisons le framework avec l’utilitaire construire_af(...) ci-dessous, calculons les extensions via Tweety, puis interprétons et expliquons les résultats obtenus.
La fonction construire_af(noms, attaques) prend une liste de noms d’arguments et une liste de paires (attaquant, attaqué) et retourne un DungTheory, représentant le graphe d’argumentation, prêt à l’emploi que nous pourrons donc analyser.
Solution 1.
from org.tweetyproject.arg.dung.syntax import DungTheory, Argument, Attackfrom org.tweetyproject.arg.dung.reasoner import ( SimpleGroundedReasoner, SimplePreferredReasoner, SimpleStableReasoner, SimpleCompleteReasoner, SimpleAdmissibleReasoner, SimpleConflictFreeReasoner,)def construire_af(noms, attaques):"""Construit un DungTheory a partir de noms d'arguments et de paires (source, cible).""" af = DungTheory() args = {nom: Argument(nom) for nom in noms}for arg in args.values(): af.add(arg)for source, cible in attaques: af.add(Attack(args[source], args[cible]))return af, argsprint("fonction utiliaire construire_af() pret.")
fonction utiliaire construire_af() pret.
Exemple guide 1 : Comparaison de sémantiques
Comparez les extensions grounded, preferred, stable et complete pour un cadre avec cycle.
a n’étant attaqué par personne, il est accepté dans toutes les sémantiques. Il neutralise b, ce qui libère c (son seul attaquant disparaît), et c neutralise à son tour d.
Les trois sémantiques convergent vers {a, c} : le framework est entièrement déterminé, sans ambiguïté. Le cycle b -> c -> d -> b est bien impair (longueur 3), mais il n’est pas isolé — a le casse en éliminant b. Un cycle impair ne pose problème à la sémantique Stable que lorsqu’aucun argument extérieur ne l’attaque.
Exercice 1
: Analyser un cadre en diamantConstruisez un cadre a -> b, a -> c, b -> d, c -> d (forme diamant)et determinez les extensions grounded et preferred.Indice : a est le seul argument non-attaque.
# Exercice 1 : Cadre en diamant# TODO etudiant : construisez le cadre et analysez# Etape 1 : definir les arguments et attaques# Etape 2 : calculer les extensions# Etape 3 : interpreter les resultatsprint("Exercice a completer")
Exercice a completer
Exercice 2
: Cycle pair vs impairConstruisez un cadre avec un cycle pair de longueur 4 et comparez CF2 et stable.Indice : a -> b -> c -> d -> a.
# Exercice 2 : Cycle pair vs impair# TODO etudiant : construisez un cycle pair et comparez# Etape 1 : definir le cadre# Etape 2 : calculer CF2 et stable# Etape 3 : comparer avec le cycle impairprint("Exercice a completer")
Exercice a completer
Exercice 3
: Statistiques personnaliseesModifiez les paramètres de generation et observez comment les sémantiques evoluent.Indice : Essayez 5 arguments avec p=0.5, puis 15 avec p=0.2.
# Exercice 3 : Statistiques personnalisees# TODO etudiant : modifiez les parametres# Etape 1 : generer avec differents parametres# Etape 2 : calculer les extensions# Etape 3 : comparer avec l'exemple guideprint("Exercice a completer")
Exercice a completer
Exemple guide 2 : CF2 vs Stable
Un cycle impair isole de longueur 5. La sémantique CF2 capture des extensions que stable ne peut pas atteindre.
Lecture des résultats — Stable vide contre CF2 informative sur le cycle impair
Stable retourne 0 extension. Pour qu’une extension stable existe, elle devrait attaquer tous les arguments extérieurs. Sur un cycle impair, aucun sous-ensemble ne peut satisfaire cette contrainte globale sans tomber sur une contradiction de parité (elle finit pas s’attaquer elle même indirectement).
CF2 retourne 5 extensions. La sémantique CF2 décompose le graphe en composantes fortement connexes (SCC) — ici une seule SCC contenant les 5 arguments. À l’intérieur, elle retient les ensembles “conflict-free” maximaux : les paires d’arguments non adjacents dans le cycle, {a,c}, {a,d}, {b,d}, {b,e}, {c,e}.
La différence fondamentale : Stable impose une contrainte globale (attaquer tout l’extérieur), CF2 impose une contrainte locale (pas de conflit interne à la SCC). CF2 garantit toujours au moins une extension, même là où Stable échoue.
Exemple guide 2bis : réparer le « vide stable » — semi-stable et ideal contre CF2
L’exemple précédent laisse un problème ouvert : stable retourne 0 extension sur le cycle impair. La littérature propose deux familles de réparation, aux philosophies opposées :
La réparation conservatrice — rester dans la hiérarchie de Dung (l’admissibilité), affaiblir la contrainte de maximalité :
semi-stable (Caminada, 2006) : extension complète qui maximise S ∪ S⁺ — l’ensemble lui-même plus tout ce qu’il attaque. Elle existe toujours, et coïncide avec stable dès que stable existe.
ideal (Dung, Mancarella & Toni, 2007) : le plus grand ensemble admissible inclus dans l’intersection de tous les preferred. Unique, toujours défini — la position sceptique maximale.
La réparation structurelle — quitter l’admissibilité et découper le graphe : CF2 (Baroni, Giacomin & Guida, 2005) décompose par composantes fortement connexes et n’impose la conflict-freedom que localement (exemple guide 2 ci-dessus).
La question : sur le même cycle impair de longueur 5, que rend chacune ? Et sur un cadre où stable existe, la réparation conservatrice dégrade-t-elle quoi que ce soit ?
Solution 4.
# Exemple guide 2bis : les deux réparations du vide stable, sur le MEME cycle impairfrom org.tweetyproject.arg.dung.reasoner import ( SimpleStableReasoner, SimpleCompleteReasoner, SimplePreferredReasoner, SimpleSemiStableReasoner, SimpleIdealReasoner, SccCF2Reasoner)af_cycle5, _ = construire_af("abcde", [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "a")])for nom, reasoner in [ ("Stable ", SimpleStableReasoner()), ("Complete ", SimpleCompleteReasoner()), ("Preferred ", SimplePreferredReasoner()), ("SemiStable", SimpleSemiStableReasoner()), ("Ideal ", SimpleIdealReasoner()), ("CF2 ", SccCF2Reasoner()),]: exts = reasoner.getModels(af_cycle5)print(f"{nom} : {exts.size()} extension(s) -> {exts}")# Controle : quand stable existe, semi-stable doit coïncider avec stable (théorème)af_temoin, _ = construire_af("abc", [("a", "b"), ("c", "b")])temoin_stable = SimpleStableReasoner().getModels(af_temoin)temoin_semistable = SimpleSemiStableReasoner().getModels(af_temoin)print("\nControle sur a -> b <- c (stable existe) :")print("Stable :", temoin_stable)print("SemiStable :", temoin_semistable)print("Coïncidence avec stable :", str(temoin_stable) ==str(temoin_semistable))
Lecture des résultats — la réparation conservatrice existe mais vide
La réparation conservatrice existe… mais de façon vide. Semi-stable et ideal retournent chacun 1 extension : l’ensemble vide. Ce n’est pas un artefact : sur ce cycle, chaque argument exige pour sa défense l’argument situé deux crans en amont (a exige d, qui exige b, en conflit avec a) — l’exigence fait le tour complet du cycle et le seul ensemble admissible complet est {}. Maximiser S ∪ S⁺ dans une famille réduite à l’ensemble vide ne peut rien rendre d’autre. La garantie d’existence tient (le théorème est vérifié : il y a bien une extension semi-stable), mais elle est ici triviale : la sémantique existe et ne dit rien.
CF2 reste seule informative : 5 extensions. En relâchant l’admissibilité au profit d’une contrainte locale par SCC, CF2 rend les paires non adjacentes du cycle — mais ses extensions ne se défendent pas nécessairement elles-mêmes.
Le contrôle confirme la coïncidence. Sur a -> b <- c, où stable existe, semi-stable = stable = {a, c} : la réparation conservatrice ne dégrade rien là où stable fonctionne déjà.
Le compromis. Semi-stable et ideal restent dans la hiérarchie de Dung — toutes les garanties dialectiques s’appliquent — au prix d’une trivialité possible sur les cycles impairs ; CF2 achète l’informativité en quittant cette hiérarchie. Aucune ne domine l’autre : le choix dépend de ce que le débat exige — des positions tranchées (CF2) ou des garanties dialectiques (semi-stable / ideal).
Exercice 4
: Modeliser un debat politiqueChoisissez un debat et modelisez-le comme cadre d’argumentation.Identifiez les extensions grounded et preferred.Indice : 5-8 arguments suffisent.
# Exercice 4 : Debat politique# TODO etudiant : definissez vos arguments et attaques# Etape 1 : identifier les arguments# Etape 2 : identifier les relations d'attaque# Etape 3 : construire le cadre et analyserprint("Exercice a completer")
Exercice a completer
Exercice 5
: Cadre avec attaques asymetriquesConstruisez un cadre ou certaines attaques sont reciproques et d’autres non.Comparez les extensions grounded et CF2.Indice : Utilisez construire_af et les reasoners du notebook.
# Exercice 5 : Cadre avec attaques asymetriques# TODO etudiant : construisez un cadre mixte# Etape 1 : definir les arguments et attaques# Etape 2 : calculer grounded et CF2# Etape 3 : comparer les resultatsprint("Exercice a completer")
Exercice a completer
Exemple guide 3 : Generation et statistiques
Generons 100 frameworks aleatoires et mesurons trois sémantiques différentes.
Solution 5.
# Exemple guide 3 : Solution completefrom org.tweetyproject.arg.dung.util import DefaultDungTheoryGenerator, DungTheoryGenerationParametersparams = DungTheoryGenerationParameters()params.numberOfArguments =10params.attackProbability =0.3generator = DefaultDungTheoryGenerator(params)N =100nb_avec_stable =0total_taille_grounded =0total_nb_preferred =0for i inrange(N): af = generator.next()ifnot SimpleStableReasoner().getModels(af).isEmpty(): nb_avec_stable +=1 total_taille_grounded += SimpleGroundedReasoner().getModel(af).size() total_nb_preferred += SimplePreferredReasoner().getModels(af).size()print(f"Sur {N} cadres aleatoires (n=10, p=0.3) :")print(f" 1. Cadres avec au moins une extension stable : {nb_avec_stable}/{N}")print(f" 2. Taille moyenne de l'extension grounded : {total_taille_grounded / N:.2f}")print(f" 3. Nombre moyen d'extensions preferred : {total_nb_preferred / N:.2f}")
Sur 100 cadres aleatoires (n=10, p=0.3) :
1. Cadres avec au moins une extension stable : 92/100
2. Taille moyenne de l'extension grounded : 0.76
3. Nombre moyen d'extensions preferred : 1.65
Lecture des résultats — statistiques de génération : 92 % de stables, grounded ~0.76
La génération étant non déterministe (aucune graine fixée, DefaultDungTheoryGenerator tire un graphe frais à chaque appel), ces valeurs varient légèrement d’une exécution à l’autre. L’exécution commitée ci-dessus donne : - 92/100 frameworks possèdent au moins une extension stable, - taille moyenne de la grounded ≈ 0.76, - nombre moyen d’extensions preferred ≈ 1.65.
Extensions stables (~92 %) : contrairement à ce qu’on pourrait attendre, la grande majorité des frameworks admettent une extension stable. À p = 0.3 sur 10 arguments, les cycles impairs isolés (sans attaquant extérieur) sont relativement rares — la densité du graphe crée suffisamment d’attaques croisées pour casser la plupart des cycles avant qu’ils n’invalident tout le graphe.
Grounded ≈ 0.76 : l’extension grounded est très petite, souvent vide ou réduite à un seul argument. Dans un graphe dense, peu d’arguments sont complètement inattaqués ou défendus sans ambiguïté ; la grounded reste prudente et ne tranche que sur les cas les plus clairs.
Preferred ≈ 1.65 : en moyenne entre 1 et 2 extensions preferred. Le graphe présente généralement quelques zones d’ambiguïté — deux camps locaux que ni l’un ni l’autre ne peut éliminer — mais pas assez pour exploser en de nombreuses extensions.
Ces trois valeurs illustrent l’écart entre les sémantiques : la grounded (≈ 0.76) est bien en dessous de la preferred (≈ 1.65 extensions, chacune souvent plus grande), confirmant que la prudence laisse beaucoup d’arguments non tranchés là où une sémantique prend position et peux plus facilement choisir des groupes.
Exemple guide 4 : Modelisation d’un debat
Modelisez un debat sur les emissions de CO2 et analysez quelles propositions survivent.
Solution 6.
# Exemple guide 4 : Solution completedebat, _ = construire_af("ABCD", [("B", "A"), ("C", "B"), ("D", "B")])grounded = SimpleGroundedReasoner().getModel(debat)preferred = SimplePreferredReasoner().getModels(debat)print("Débat initial")print(" Grounded :", grounded)print(" Nombre d'extensions preferred :", preferred.size())# Ajout de l'argument E : E attaque Ddebat2, _ = construire_af("ABCDE", [("B", "A"), ("C", "B"), ("D", "B"), ("E", "D")])print("\nAprès ajout de E (E -> D)")print(" Grounded :", SimpleGroundedReasoner().getModel(debat2))
Débat initial
Grounded : {A,C,D}
Nombre d'extensions preferred : 1
Après ajout de E (E -> D)
Grounded : {A,C,E}
Lecture des résultats — le débat émissions : un seul défenseur suffit
Débat initial :C et D sont acceptés (pas d’attaquants) et neutralisent tous les deux B, qui ne peut donc plus attaquer A. L’extension grounded est {A, C, D} : la thèse de réduction des émissions est acceptée.
Après ajout de E :E est accepté (pas d’attaquant) et neutralise D. Mais C attaque toujours B seul — B reste rejeté. La grounded devient {A, C, E} : A reste accepté.
Ce résultat illustre une propriété importante : lorsque plusieurs arguments défendent la même conclusion (C et D attaquent tous les deux B), un seul suffit. Supprimer ou réfuter un argument redondant ne change pas la conclusion finale.
Exemple guide 5 : Symetrie parfaite
Un cadre parfaitement symetrique ou toutes les attaques sont reciproques.
Solution 7.
# Exemple guide 5 : Solution completesym, _ = construire_af("abcd", [ ("a", "b"), ("b", "a"), # a <-> b ("c", "d"), ("d", "c"), # c <-> d ("a", "c"), ("c", "a"), # a <-> c ("b", "d"), ("d", "b"), # b <-> d])resultats = {"Conflict-Free": SimpleConflictFreeReasoner().getModels(sym),"Admissible": SimpleAdmissibleReasoner().getModels(sym),"Complete": SimpleCompleteReasoner().getModels(sym),"Preferred": SimplePreferredReasoner().getModels(sym),"Stable": SimpleStableReasoner().getModels(sym),}for nom, exts in resultats.items():print(f"{nom:14s}: {exts.size()} extension(s) -> {exts}")print(f"{'Grounded':14s}:", SimpleGroundedReasoner().getModel(sym))
Lecture des résultats — symétrie parfaite : deux extensions, aucun camp dominant
Grounded = {} : aucun argument n’est incontestable, la position sceptique ne tranche pas.
Conflict-Free = Admissible : dans un framework symétrique sans auto-attaque, tout ensemble conflict-free se défend automatiquement lui-même. Les deux sémantiques coïncident.
Stable = Preferred = 2 extensions : les deux ensembles indépendants maximaux du carré sont {a, d} et {b, c} — les deux diagonales. Chaque coalition attaque l’autre en totalité et se défend en totalité.
La symétrie du graphe se transpose directement dans les extensions : deux solutions symétriques, aucune ne dominant l’autre. C’est la structure formelle d’un désaccord insolvable à deux camps.
Ce que ces exercices montrent
Exercice
Idée retenue
1
Un cycle impair n’est problématique que s’il est isolé : un attaquant externe le casse et restaure une extension stable.
2
Stable (contrainte globale) échoue sur un cycle impair isolé ; CF2 (contrainte locale par SCC) retourne toujours des extensions.
3
Sur des frameworks aléatoires denses, la grande majorité des frameworks admettent une extension stable (seuls les cycles impairs isolés font exception, cf. interprétation ci-dessus) et la grounded est souvent petite.
4
Un argument est accepté dès que toutes ses objections sont réfutées ; un argument redondant peut disparaître sans changer la conclusion.
5
La symétrie du graphe se reflète directement dans les extensions : Conflict-Free = Admissible, et Stable/Preferred retournent exactement les deux coalitions symétriques.
En résumé : les sémantiques encodent des niveaux de prudence différents, de la Grounded (sceptique, unique) à la Stable (exigeante, parfois inexistante).
Resume et Conclusion
Ce notebook a presente les cadres d’argumentation abstraits de Dung (1995), qui constituent le fondement de l’argumentation computationnelle moderne, ainsi que les nouveautes de Tweety v1.30.
Systèmes d’aide a la decision (arguments pour/contre traitements)
IA multi-agents
Negociation et protocoles de consensus
Debat politique
Analyse de positions et arguments contradictoires
XAI (v1.30)
Explications de decisions automatisees
Diagnostic causal (v1.30)
Raisonnement medical et scientifique
Comparaison des sémantiques (rappel)
ConflictFree (base)
|
v
Admissible (defense)
|
v
Complete (point fixe)
|
+-- Grounded (minimal, unique, sceptique)
|
+-- Preferred (maximal, credule)
|
+-- Stable (attaque tout externe, peut ne pas exister)
Prochaines étapes
Le notebook Tweety-6-Structured-Argumentation explore comment integrer la structure interne des arguments avec : - ASPIC+ : Règles strictes et defaisables - DeLP : Programmation logique defaisable - ABA : Argumentation basee sur les assumptions - ASP : Answer Set Programming avec Clingo
Ces approches combinent la puissance des sémantiques de Dung avec la richesse de la logique formelle.