Découvrir les Abstract Dialectical Frameworks (ADF) et leurs conditions d’acceptation
Maîtriser les frameworks bipolaires (Evidential, Necessity)
Explorer les frameworks pondérés (WAF) et sociaux (SAF)
Comprendre les Set Argumentation Frameworks (attaques collectives)
Appréhender les frameworks étendus avec attaques sur attaques (EAF/REAF)
Prérequis
Ce notebook utilise le module partagé tweety_init.py pour l’initialisation JVM.
Durée estimée : 50 minutes
Note technique : Les solveurs SAT natifs (NativeMinisatSolver, NativeLingelingSolver, NativePicosatSolver) sont automatiquement chargés grâce au dossier libs/native/ configuré dans le classpath.
Frameworks Bipolaires : Introduction des relations de support (Evidential vs Necessity)
Frameworks Pondérés (WAF) : Poids sur les attaques avec seuils de tolérance
Frameworks Sociaux (SAF) : Votes positifs/négatifs et propagation de scores
Attaques collectives et récursives : SetAF (ensembles attaquants) et EAF/REAF (meta-attaques)
Chaque section illustre une extension différente des cadres de Dung classiques, avec des applications pratiques variées.
Partie 5a : Frameworks d’Argumentation Étendus
Cette section explore des extensions complexes des cadres de Dung, permettant de modéliser des scénarios de raisonnement plus riches avec des conditions d’acceptation spécifiques, des relations de support, des poids, et des attaques collectives ou récursives.
5.1 Abstract Dialectical Frameworks (ADF)
Les ADF [Brewka & Woltran, 2010] généralisent les cadres de Dung.
Origine. Les Abstract Dialectical Frameworks (ADF) sont introduits par Brewka, G. & Woltran, S. (2010), Abstract dialectical frameworks, Proceedings of KR 2010, pp. 102-111 — qui généralisent les cadres de Dung en remplaçant les attaques binaires par une condition d’acceptation propositionnelle par argument (les formulations de 2013 et ultérieures en sont des extensions). Au lieu d’attaques binaires, chaque argument (ou statement) porte une condition d’acceptation : une formule propositionnelle sur ses parents. Les sémantiques ADF sont trivaluées : chaque statement reçoit la valeur t (vrai/accepté), f (faux/rejeté) ou u (indécis / undecided). Tweety classe en outre chaque lien parent → statement selon sa nature — attaquant, supportant, dépendant (les deux selon le contexte) ou redondant — ce qui est précisément ce qui généralise Dung : un lien purement attaquant correspond à une attaque de Dung, tandis que les liens supportants et dépendants ajoutent une expressivité que Dung n’a pas.
Sémantiques : Admissible, Complete, Grounded, Preferred, Stable (toutes trivaluées) Module Tweety : arg.adf — les types de liens sont calculés par SatLinkStrategy, qui teste via un solveur SAT, pour chaque parent, s’il peut faire basculer la valeur de la condition d’acceptation
IMPORTANT - Solveurs SAT Natifs: Le raisonnement ADF nécessite un solveur SAT incrémental natif. TweetyProject supporte MiniSat, Lingeling, et PicoSAT via JNI.
Prérequis : Les bibliothèques natives doivent être dans java.library.path : - Windows : minisat.dll, lingeling.dll, picosat.dll - Linux : minisat.so, lingeling.so, picosat.so
Ces fichiers sont fournis dans libs/native/ et automatiquement chargés si Tweety-1-Setup est exécuté.
# --- 5.1 Abstract Dialectical Frameworks (ADF) ---print("\n--- 5.1 Abstract Dialectical Frameworks (ADF) ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Execution de l'exemple ADF...")print("\n=== Test des solveurs SAT natifs ===")# Verifier si java.library.path inclut les libs nativestry:import jpype java_lib_path = jpype.java.lang.System.getProperty("java.library.path")print(f"java.library.path: {java_lib_path[:100]}..."iflen(java_lib_path) >100elsef"java.library.path: {java_lib_path}")except:print("Impossible de lire java.library.path") adf_imports_ok =False native_solver_available =False native_solver_name =Nonetry:from jpype.types import*from java.io import Filefrom java.util import Collectionfrom org.tweetyproject.arg.adf.syntax.adf import AbstractDialecticalFrameworkfrom org.tweetyproject.arg.adf.syntax import Argument as AdfArgumentfrom org.tweetyproject.arg.adf.syntax.acc import AcceptanceCondition, NegationAcceptanceConditionfrom org.tweetyproject.arg.adf.io import KppADFFormatParserfrom org.tweetyproject.arg.adf.semantics.link import SatLinkStrategy, LinkStrategyfrom org.tweetyproject.arg.adf.semantics.interpretation import Interpretationfrom org.tweetyproject.arg.adf.reasoner import AdmissibleReasoner, CompleteReasoner, GroundReasonerfrom org.tweetyproject.logics.pl.sat import Sat4jSolverfrom org.tweetyproject.arg.adf.sat import IncrementalSatSolverprint("Imports ADF de base reussis.") adf_imports_ok =True# Tenter de charger les solveurs natifs dans l'ordre de preference adf_solver =None solvers_to_try = [ ("NativeMinisatSolver", "org.tweetyproject.arg.adf.sat.solver.NativeMinisatSolver"), ("NativeLingelingSolver", "org.tweetyproject.arg.adf.sat.solver.NativeLingelingSolver"), ("NativePicosatSolver", "org.tweetyproject.arg.adf.sat.solver.NativePicosatSolver"), ]print("\nTentative de chargement des solveurs SAT natifs:")for solver_name, solver_class_name in solvers_to_try:try: SolverClass = jpype.JClass(solver_class_name) adf_solver = SolverClass() native_solver_available =True native_solver_name = solver_nameprint(f" OK {solver_name} charge avec succes!")breakexcept jpype.JException as e_java: err_msg =str(e_java.message()) ifhasattr(e_java, 'message') elsestr(e_java)if"UnsatisfiedLinkError"in err_msg or"no "in err_msg.lower():print(f" -- {solver_name}: DLL/SO non trouve (java.library.path)")else:print(f" -- {solver_name}: {err_msg[:60]}...")exceptExceptionas e:print(f" -- {solver_name}: {e}")ifnot native_solver_available:print("\nAucun solveur SAT natif disponible.")print(" Les DLLs (minisat.dll, lingeling.dll, picosat.dll) doivent etre")print(" dans java.library.path. Verifiez que Tweety-1-Setup a configure NATIVE_LIBS_DIR.")print("\n Fallback vers Sat4jSolver (NON incremental)...") adf_solver = Sat4jSolver()print(f"\nSolveur selectionne: {adf_solver.getClass().getSimpleName()}")# Tester si le solveur est incremental IncrementalSatSolver_class = jpype.JClass("org.tweetyproject.arg.adf.sat.IncrementalSatSolver") is_incremental =isinstance(adf_solver, IncrementalSatSolver_class)print(f"Est incremental: {is_incremental}")if is_incremental:print("\n=== Test ADF avec solveur incremental ===") link_strategy = SatLinkStrategy(adf_solver)print("SatLinkStrategy creee avec succes.")# Arguments ADF - note: Argument implemente AcceptanceCondition a = AdfArgument("a") b = AdfArgument("b") c = AdfArgument("c")# ADF: a accepte si non-b, b accepte si non-c, c toujours accepte# NegationAcceptanceCondition prend un AcceptanceCondition (Argument en est un) builder = AbstractDialecticalFramework.builder() builder.add(a, NegationAcceptanceCondition(b)) # a accepte si NOT b builder.add(b, NegationAcceptanceCondition(c)) # b accepte si NOT c builder.add(c, AcceptanceCondition.TAUTOLOGY) # c toujours accepte adf = builder.lazy(link_strategy).build()print(f"\nADF cree avec {adf.size()} arguments:")for arg in adf.getArguments(): acc = adf.getAcceptanceCondition(arg)print(f" {arg}: {acc}")# Raisonnementprint("\nCalcul des extensions:")try: grounded_reasoner = GroundReasoner(adf_solver) grounded = grounded_reasoner.getModel(adf)print(f" Grounded: {grounded}")exceptExceptionas e:print(f" Erreur calcul Grounded: {e}")print("\nOK Test ADF avec solveur SAT natif reussi!")else:print("\nCONCLUSION: Le raisonnement ADF necessite un solveur SAT incremental natif.")print(" Sat4jSolver n'est pas incremental, donc ADF ne peut pas fonctionner.")print(" Solution: Assurez-vous que NATIVE_LIBS_DIR est configure dans Tweety-1-Setup")print(" et que la JVM est redemarree apres modification.")exceptImportErroras e:print(f"Erreur d'import pour ADF : {e}. Verifiez le JAR 'arg.adf'.")except jpype.JException as e_java:print(f"Erreur Java generale: {e_java.message()}")print(e_java.stacktrace())exceptExceptionas e_gen:print(f"Erreur Python inattendue: {e_gen}")import traceback traceback.print_exc()
--- 5.1 Abstract Dialectical Frameworks (ADF) ---
JVM prete. Execution de l'exemple ADF...
=== Test des solveurs SAT natifs ===
java.library.path: <repo>MyIA.AI.Notebooks\SymbolicAI\Argument_Analysis\libs\native
Imports ADF de base reussis.
Tentative de chargement des solveurs SAT natifs:
OK NativeMinisatSolver charge avec succes!
Solveur selectionne: NativeMinisatSolver
Est incremental: True
=== Test ADF avec solveur incremental ===
SatLinkStrategy creee avec succes.
ADF cree avec 3 arguments:
a: neg(b)
c: T
b: neg(c)
Calcul des extensions:
Grounded: {t(a) t(c) f(b)}
OK Test ADF avec solveur SAT natif reussi!
Exemple pratique : ADF avec conditions d’acceptation
L’exemple suivant crée un ADF simple avec 3 arguments et des conditions de négation. Le code vérifie également la disponibilité des solveurs SAT natifs, qui sont essentiels pour le fonctionnement des ADF.
Objectif : Démontrer que les ADF peuvent exprimer des conditions plus complexes qu’un simple graphe d’attaques.
Interpretation des résultats ADF
L’ADF créé modelise une chaîne de dependances negatives :
c (toujours accepte) --[nie]--> b --[nie]--> a
Conditions d’acceptation : - c: T (tautologie) : c est inconditionellement accepte - b: neg(c) : b est accepte si et seulement si c est rejete - a: neg(b) : a est accepte si et seulement si b est rejete
Extension Grounded (trivaluee) : {t(a) t(c) f(b)}
La sémantique grounded d’un ADF est trivaluee : chaque statement recoit t (vrai/accepte), f (faux/rejete) ou u (indecis). C’est le plus petit point fixe de l’opérateur caractéristique. Ici la chaîne de conditions est déterministe, donc aucun statement ne reste u ; sur des conditions cycliques (ex. a: neg(a)), grounded affecterait la valeur u.
Argument
Statut
Explication
c
t (true/accepte)
Condition = T, donc toujours vrai
b
f (false/rejete)
Condition = neg(c), mais c=t, donc b=f
a
t (true/accepte)
Condition = neg(b), et b=f, donc a=t
Différence avec Dung - les types de liens : Dans un framework de Dung classique, on aurait défini des attaques c -> b et b -> a. L’ADF remplace les attaques binaires par des conditions d’acceptation, et classe chaque lien parent -> statement selon sa nature, calculee ici par SatLinkStrategy : - attaquant : rendre le parent vrai tend a rendre la condition fausse (ici neg(c) rend le lien c -> b attaquant) ; - supportant : rendre le parent vrai tend a rendre la condition vraie ; - dependant : le parent peut etre attaquant ou supportant selon la valeur des autres parents ; - redondant : le parent n’influence pas la condition.
Un ADF dont tous les liens sont purement attaquants est un cadre de Dung : c’est en ce sens que les ADF generalisent Dung, en ajoutant supports, dependances et conditions complexes (conjonctions, disjonctions, implications) pour chaque argument.
Applications : - Modelisation de règles metier avec exceptions - Systèmes de configuration avec contraintes dependantes - Raisonnement juridique avec conditions cumulatives
Transition : De la logique aux relations de support
Les ADF permettent d’exprimer des conditions d’acceptation complexes, mais restent dans un paradigme “logique”. Les frameworks bipolaires introduisent un nouveau concept : le support.
Au lieu de seulement attaquer, les arguments peuvent maintenant soutenir d’autres arguments. Cette extension modélise mieux les débats réels où on trouve à la fois des arguments “pour” et “contre”.
Deux philosophies : - Evidential : Un seul support suffit (disjonctif) - Necessity : Tous les supports requis (conjonctif)
5.2 Frameworks Bipolaires (Evidential, Necessity)
Les cadres d’argumentation bipolaires etendent les AAFs de Dung en introduisant une relation de support distincte de l’attaque. Tweety implemente deux variantes principales :
Origine. Les frameworks d’argumentation bipolaires (BAF) — qui ajoutent une relation de support (deductive, evidential ou necessity) à la relation d’attaque — sont introduits par Cayrol, C. & Lagasquie-Schiex, M.-C. (2005), On the acceptability of arguments in bipolar argumentation frameworks. Les deux variantes implementees ici (Evidential AF, disjonctif ; Necessity AF, conjonctif) correspondent aux deux principaux modes de support formalises ulterieurement dans cette ligne de travail.
Variante
Support
Caractéristique
Evidential AF
Disjonctif
Un seul supportant suffit + arguments “prima facie”
Necessity AF
Conjonctif
Tous les supportants requis
Module Tweety : arg.bipolar
5.2a Evidential Argumentation Framework
Dans l’Evidential AF, les arguments peuvent etre : - Prima facie : Acceptes par defaut (supportes par l’argument special eta) - Derives : Necessitent au moins un support
L’exemple ci-dessous créé un framework avec 6 arguments, des attaques mutuelles, et un support d -> e.
# --- 5.2a Evidential Argumentation Framework ---print("\n--- 5.2a Evidential Argumentation Framework ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Execution de l'exemple Evidential AF...")try:import jpypefrom jpype.types import*from java.util import HashSet, Collection, Set as JavaSetfrom org.tweetyproject.arg.dung.syntax import Argumentfrom org.tweetyproject.arg.bipolar.syntax import ( EvidentialArgumentationFramework, BArgument, ArgumentSet, SetAttack, SetSupport )from org.tweetyproject.arg.bipolar.reasoner.evidential import ( SelfSupportingReasoner, GroundedReasoner as EvidentialGroundedReasoner, PreferredReasoner as EvidentialPreferredReasoner )print("Imports Evidential AF reussis.")# Creation du framework Evidential et = EvidentialArgumentationFramework() args_ev = {name: BArgument(name) for name in"abcdef"}for arg in args_ev.values(): et.add(arg)# Attaques attack_b_a = SetAttack(args_ev['b'], args_ev['a']) attack_b_c = SetAttack(args_ev['b'], args_ev['c']) attack_c_b = SetAttack(args_ev['c'], args_ev['b']) attack_c_d = SetAttack(args_ev['c'], args_ev['d']) attack_d_f = SetAttack(args_ev['d'], args_ev['f']) attack_f_f = SetAttack(args_ev['f'], args_ev['f']) # Self-attack# Support support_d_e = SetSupport(args_ev['d'], args_ev['e'])print(" Ajout des attaques et supports...") attacks_et = et.getAttacks() supports_et = et.getSupports() attacks_et.add(attack_b_a); attacks_et.add(attack_b_c) attacks_et.add(attack_c_b); attacks_et.add(attack_c_d) attacks_et.add(attack_d_f); attacks_et.add(attack_f_f) supports_et.add(support_d_e)# Arguments Prima Facie (supportes par eta) et.addPrimaFacie(args_ev['b']) et.addPrimaFacie(args_ev['c']) et.addPrimaFacie(args_ev['d']) et.addPrimaFacie(args_ev['f'])print("\nFramework Evidential cree:")print(str(et.prettyPrint()))print("\nCalcul des extensions Evidential:")try: ss_models = SelfSupportingReasoner().getModels(et)print(f" - Self-Supporting ({ss_models.size()} ensembles): {ss_models}")print(f" - Grounded: {EvidentialGroundedReasoner().getModels(et)}")print(f" - Preferred: {EvidentialPreferredReasoner().getModels(et)}")exceptExceptionas e_ev_reason: print(f"Erreur raisonnement Evidential: {e_ev_reason}")exceptImportErroras e: print(f"Erreur d'import Evidential: {e}.")except jpype.JException as e_java: print(f"Erreur Java: {e_java.message()}")exceptExceptionas e_gen: print(f"Erreur Python: {e_gen}")import traceback traceback.print_exc()
Le code suivant construit un Evidential AF avec : - 6 arguments (a à f) - Des attaques binaires entre arguments - Un support d -> e - Des arguments prima facie (b, c, d, f) qui sont “auto-justifiés”
Tweety ajoute automatiquement l’argument spécial eta pour représenter la source de vérité initiale.
5.2b Necessity Argumentation Framework
Contrairement a l’Evidential AF ou un seul support suffit, le Necessity AF exige que tous les supportants soient presents pour qu’un argument soit accepte.
Caractéristiques : - Support conjonctif : {a, b} -> c signifie que c necessite a ET b - Pas d’argument eta special - Le self-support a -> a permet a un argument de “s’auto-justifier”
# --- 5.2b Necessity Argumentation Framework ---print("\n--- 5.2b Necessity Argumentation Framework ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Execution de l'exemple Necessity AF...")try:import jpypefrom jpype.types import*from java.util import HashSet, Set as JavaSetfrom org.tweetyproject.arg.bipolar.syntax import ( NecessityArgumentationFramework, BArgument, ArgumentSet, BinaryAttack, BinarySupport, SetSupport )from org.tweetyproject.arg.bipolar.reasoner.necessity import ( GroundedReasoner as NecessityGroundedReasoner, PreferredReasoner as NecessityPreferredReasoner )print("Imports Necessity AF reussis.")# Creation du framework Necessity nt = NecessityArgumentationFramework() args_nec = {name: BArgument(name) for name in"abcde"}for arg in args_nec.values(): nt.add(arg)# Attaques binaires attack_b_a_n = BinaryAttack(args_nec['b'], args_nec['a']) attack_e_a_n = BinaryAttack(args_nec['e'], args_nec['a']) attack_c_d_n = BinaryAttack(args_nec['c'], args_nec['d'])# Supports binaires support_a_c_n = BinarySupport(args_nec['a'], args_nec['c']) support_b_b_n = BinarySupport(args_nec['b'], args_nec['b']) # Self-support# Support ensembliste: {b, d} -> e supportants_s3 = ArgumentSet() supportants_s3.add(args_nec['b']) supportants_s3.add(args_nec['d']) supportes_s3 = HashSet() supportes_s3.add(args_nec['e']) support_set_n = SetSupport(supportants_s3, JObject(supportes_s3, JavaSet))print(" Ajout des attaques et supports...") attacks_nt = nt.getAttacks() supports_nt = nt.getSupports() attacks_nt.add(attack_b_a_n) attacks_nt.add(attack_e_a_n) attacks_nt.add(attack_c_d_n) supports_nt.add(support_a_c_n) supports_nt.add(support_b_b_n) supports_nt.add(support_set_n)print("\nFramework Necessity cree:")print(str(nt.prettyPrint()))print("\nCalcul des extensions Necessity:")try:print(f" - Grounded: {NecessityGroundedReasoner().getModels(nt)}")print(f" - Preferred: {NecessityPreferredReasoner().getModels(nt)}")exceptExceptionas e_nec_reason: print(f"Erreur raisonnement Necessity: {e_nec_reason}")exceptImportErroras e: print(f"Erreur d'import Necessity: {e}.")except jpype.JException as e_java: print(f"Erreur Java: {e_java.message()}")exceptExceptionas e_gen: print(f"Erreur Python: {e_gen}")import traceback traceback.print_exc()
--- 5.2b Necessity Argumentation Framework ---
JVM prete. Execution de l'exemple Necessity AF...
Imports Necessity AF reussis.
Ajout des attaques et supports...
Framework Necessity cree:
argument(a).
argument(b).
argument(c).
argument(d).
argument(e).
Calcul des extensions Necessity:
- Grounded: [{a,b,c,d,e}]
- Preferred: [{a,b,c,d,e}]
Interpretation des Frameworks Bipolaires
L’argument mysterieux eta
Dans l’Evidential AF, un argument special eta (eta) apparait automatiquement. C’est l’argument evidential qui represente la “source de verite” initiale. Les arguments prima facie (b, c, d, f) sont supportes par eta, ce qui leur donne une base d’acceptation independante.
eta --[supporte]--> {b, c, d, f} (prima facie)
Comparaison Evidential vs Necessity
Aspect
Evidential AF
Necessity AF
Support
Ensembliste (un supportant suffit)
Ensembliste (tous requis)
Prima facie
Arguments auto-supportes via eta
Pas de concept equivalent
Self-Supporting
17 ensembles possibles
N/A
Extension Grounded
{b,c,d,f,eta}
{a,b,c,d,e}
Analyse Evidential AF
Self-Supporting (17 ensembles) : Tous les sous-ensembles qui peuvent se “justifier”
Grounded {b,c,d,f,eta} : Les prima facie + eta forment la base minimale
L’argument a n’est pas prima facie et est attaque par b, donc exclu
L’argument e depend du support de d (qui est attaque par c)
Analyse Necessity AF
Extension {a,b,c,d,e} : Tous les arguments sont acceptes
Le support {b,d} -> e est satisfait car b et d sont presents
Le self-support b -> b permet a b de “s’auto-justifier”
Application pratique
Evidential : Modelise les preuves juridiques (une preuve suffit)
Necessity : Modelise les prerequis (tous les cours requis pour un diplome)
Transition : Introduction des poids
Les frameworks bipolaires ajoutent les relations de support, mais traitent toutes les attaques comme équivalentes. Dans la réalité, certaines attaques sont plus fortes que d’autres.
Les Frameworks Pondérés (WAF) associent un poids numérique à chaque attaque. L’acceptabilité d’un argument dépend alors : - Du poids cumulé des attaques qu’il reçoit - Des seuilsalpha (défense minimale) et gamma (attaque minimale)
Applications : - Débats avec arguments de différentes forces - Coûts de résolution de conflits - Probabilités d’attaques
5.3 Frameworks Pondérés (WAF)
Les Cadres d’Argumentation Pondérés (Weighted Argumentation Frameworks - WAF) associent un poids à chaque attaque, représentant sa force ou son coût. L’évaluation de l’acceptabilité prend en compte ces poids via des seuils ou des agrégations.
Tweety utilise la structure des semi-anneaux (Semiring) pour définir comment les poids sont interprétés: - WeightedSemiring: Poids numériques sommés (coûts) - FuzzySemiring: Degrés de vérité dans [0, 1] - ProbabilisticSemiring: Probabilités
Sémantique (alpha, gamma) - relaxation de Bistarelli, Rossi & Santini
Le raisonneur SimpleWeightedAdmissibleReasoner de Tweety implemente la relaxation a deux seuils de Bistarelli, Rossi & Santini (ECSQARU 2017 ; IJAR 2018), qui prolonge les weighted argument systems de Dunne et al. (2011). Les deux paramètres ne sont pas un seuil de defense et un seuil d’attaque ; d’après le code source (WeightedArgumentationFramework.isAlphaGammaAdmissible) :
alpha : poids maximal tolere des attaques internes a l’ensemble (relaxation de l’absence de conflit). Avec alpha = 0, l’ensemble doit etre strictement sans conflit interne. C’est le seuil teste par isAlphaConflictFree.
gamma : seuil de defense = différence maximale toleree entre le poids agrege des attaques et celui des defenses. Avec gamma = 0, la defense d’un argument doit etre au moins aussi forte que les attaques subies (attaque - defense <= 0). C’est le seuil teste par gDefence.
Pourquoi les ensembles ponderes sont-ils vides - et pourquoi alpha : 0 -> 15 ne change rien ?
Les sorties (a=0, g=0) : [] puis (a=15, g=0) : [] sont coherentes une fois la sémantique comprise : augmenter alpha ne relache que la tolerance au conflit interne, alors que la contrainte bloquante ici est la defense (gamma = 0, inchangee). Tant que gamma n’est pas relache, le résultat reste vide - relacher alpha seul est sans effet. De plus, gDefence renvoie faux lorsqu’un ensemble ne subit aucune attaque externe pertinente : l’ensemble vide et les singletons non attaques (ex. {a}, qui n’est attaque par personne) echouent donc le test de defense sous ces reglages stricts. C’est ce qui rend la sémantique ponderee (0 ensemble) bien plus restrictive que l’admissibilite standard de Dung (6 ensembles).
Attaques ponderees du graphe (telles que construites dans le code) :
a --7.0--> b
c --8.0--> b
c --9.0--> d d --8.0--> c (attaque mutuelle c <-> d)
d --5.0--> e
e --6.0--> e (auto-attaque)
Sémantique
Admissibles
Grounded
Standard (Dung)
6 : {}, {a}, {c}, {d}, {a,c}, {a,d}
{a}
Pondere (alpha=0, gamma=0)
0
{}
Pour obtenir des ensembles non vides
Il faut relacher gamma (le seuil de defense) au-dela du plus grand ecart attaque/defense du graphe - et non augmenter alpha. La valeur exacte depend des poids ; elle n’est pas exercee dans ce notebook (laissee en exercice). Le alpha=20.0 recommande dans une version anterieure de cette cellule etait un ajustement jamais teste, et portait de surcroit sur le mauvais paramètre.
Sources : P. Dunne, A. Hunter, P. McBurney, S. Parsons, M. Wooldridge, Weighted argument systems: Basic definitions, illustrations, and emerging results (Artificial Intelligence, 2011) ; S. Bistarelli, F. Rossi, F. Santini, A relaxation of internal conflict and defence in weighted argumentation frameworks (ECSQARU 2017) et A novel weighted defence and its relaxation in abstract argumentation (IJAR, 2018).
Exercice : Debat avec attaques ponderees (WAF)
La section 5.3 a montre les Frameworks Ponderes avec seuils alpha et gamma. Modelisez un debat ou certaines attaques sont plus fortes que d’autres.
Contexte
Trois experts : a (“Investir maintenant”), b (“Le marche est instable”, attaque a, poids 6.0), c (“Les indicateurs sont solides”, attaque b, poids 9.0).
# --- Exercice : Debat avec attaques ponderees (WAF) ---# TODO etudiant : modelisez un debat d'experts avec des attaques ponderees## Etape 1 : imports (cf section 5.3)# from org.tweetyproject.arg.weighted.syntax import WeightedArgumentationFramework# from org.tweetyproject.arg.dung.syntax import Argument, Attack, DungTheory# from org.tweetyproject.math.algebra import WeightedSemiring# from org.tweetyproject.arg.weighted.reasoner import SimpleWeightedGroundedReasoner# from org.tweetyproject.arg.dung.reasoner import SimpleGroundedReasoner## Etape 2 : creer le semiring et le WeightedArgumentationFramework# Etape 3 : ajouter a, b, c puis les attaques ponderees b->a (6.0), c->b (9.0)# Etape 4 : calculer le grounded pondere (alpha=0, gamma=0) ET le grounded standard# Etape 5 (bonus) : faire varier alpha (ex: 10.0) et observer l'effetifnot jvm_ready:print("ERREUR: JVM non demarree.")else: waf =None# TODO etudiant : remplacer par le WeightedArgumentationFramework grounded_pondere =None# TODO etudiant : remplacer par le grounded pondere grounded_standard =None# TODO etudiant : remplacer par le grounded standardprint("Exercice a completer")
Exercice a completer
5.4 Frameworks Sociaux (SAF)
Les Cadres d’Argumentation Sociaux (SAF) [Leite, Martins, 2011] permettent d’associer des votes (positifs ou négatifs) aux arguments. Ces votes influencent la force ou l’acceptabilité finale des arguments.
Sémantique ISS (Iterated Schema Semantics): Calcule un score pour chaque argument basé sur les scores de ses attaquants et sur les votes, jusqu’à convergence.
# --- 5.4 Frameworks Sociaux (SAF) ---print("\n--- 5.4 Frameworks Sociaux (SAF) ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Execution de l'exemple SAF...") saf_imports_ok =Falsetry:import jpypefrom jpype.types import*try:from org.tweetyproject.arg.social.syntax import SocialAbstractArgumentationFrameworkfrom org.tweetyproject.arg.dung.syntax import Argument, Attackfrom org.tweetyproject.arg.social.reasoner import IssReasonerfrom org.tweetyproject.arg.social.semantics import SimpleProductSemanticsprint("Imports SAF directs reussis.") saf_imports_ok =TrueexceptImportError:print("Imports directs SAF echoues. Tentative avec JClass...") SocialAbstractArgumentationFramework = jpype.JClass("org.tweetyproject.arg.social.syntax.SocialAbstractArgumentationFramework") Argument = jpype.JClass("org.tweetyproject.arg.dung.syntax.Argument") Attack = jpype.JClass("org.tweetyproject.arg.dung.syntax.Attack") IssReasoner = jpype.JClass("org.tweetyproject.arg.social.reasoner.IssReasoner") SimpleProductSemantics = jpype.JClass("org.tweetyproject.arg.social.semantics.SimpleProductSemantics")print("Imports SAF via JClass reussis.") saf_imports_ok =Truefrom java.util import Collectionif saf_imports_ok: saf = SocialAbstractArgumentationFramework() A = Argument("A"); B = Argument("B"); C = Argument("C"); D = Argument("D") saf.add(A); saf.add(B); saf.add(C); saf.add(D)try:# NB: saf.getAttacks() retourne une COPIE DEFENSIVE chez# SocialAbstractArgumentationFramework -> .add() dessus ne modifie# PAS le framework (les attaques restent absentes, ISS tourne sans# propagation). On ajoute directement via addAttack(attacker, attacked). saf.addAttack(A, B); saf.addAttack(B, C) saf.addAttack(C, B); saf.addAttack(C, D)print(" Attaques ajoutees avec succes.")# Votes saf.voteUp(A, 3); saf.voteDown(A, 1) # A: +2 net saf.voteUp(B, 2) # B: +2 net saf.voteUp(C, 2); saf.voteDown(C, 5) # C: -3 net saf.voteUp(D, 2); saf.voteDown(D, 1) # D: +1 netprint("\nFramework Social (SAF) cree:")print(str(saf))print("\nCalcul du modele avec ISS (Iterated Schema Semantics)...")try: iss_reasoner = IssReasoner(SimpleProductSemantics(0.01), 0.001) iss_model = iss_reasoner.getModel(saf)print("\nModele ISS (scores d'acceptabilite):\n", str(iss_model))except jpype.JException as e_iss_java: print(f"Erreur Java lors du raisonnement ISS: {e_iss_java.message()}")exceptExceptionas e_iss_py: print(f"Erreur Python lors du raisonnement ISS: {e_iss_py}")exceptExceptionas e_add_attack:print(f"Erreur lors de l'ajout d'attaques via getAttacks().add(): {e_add_attack}")exceptImportErroras e: print(f"Erreur d'import initiale pour SAF : {e}.")except jpype.JException as e_java: print(f"Erreur Java generale: {e_java.message()}")exceptExceptionas e_gen: print(f"Erreur Python inattendue: {e_gen}");import traceback; traceback.print_exc()
--- 5.4 Frameworks Sociaux (SAF) ---
JVM prete. Execution de l'exemple SAF...
Imports SAF directs reussis.
Attaques ajoutees avec succes.
Framework Social (SAF) cree:
<{A(+3-1),B(+2-0),C(+2-5),D(+2-1)},[(B,C), (C,B), (A,B), (C,D)]>
Calcul du modele avec ISS (Iterated Schema Semantics)...
Modele ISS (scores d'acceptabilite):
{A=0.7481296758104738, B=0.19288319912917049, C=0.23027583477056476, D=0.5114446280594254}
Interpretation des scores ISS
Le modèle ISS (Iterated Schema Semantics) calcule un score d’acceptabilite pour chaque argument :
Scores obtenus :
Argument
Score
Votes (up-down)
Interpretation
A
0.748
+3 -1 = +2
Bien accepte ; A n’est attaque par personne
B
0.193
+2 -0 = +2
Fortement penalise : attaque par A (0.748) ET C (0.230)
C
0.230
+2 -5 = -3
Faible : votes negatifs (-3) ET attaque par B
D
0.511
+2 -1 = +1
Modere : attaque par C (0.230), attaquant faible
Mécanisme ISS :
Score initial base sur les votes : score = up / (up + down)
Propagation via les attaques : le score d’un argument diminue si ses attaquants ont des scores eleves
Itération jusqu’a convergence (epsilon = 0.001)
Analyse du graphe : - A -> B et B -> C et C -> B et C -> D - B est attaque par A (score 0.748) et C (score 0.230) : la double attaque, dont l’attaquant A est fort, fait chuter B a 0.193 malgre ses +2 votes. - A (0.748) n’a aucun attaquant : son score ne depend que de ses propres votes. - C (0.230) subit ses votes negatifs (-3) ET l’attaque de B.
Application pratique : - Modeliser les debats sur reseaux sociaux (likes/dislikes) - Les arguments populaires (beaucoup de upvotes) resistent mieux aux attaques - Un argument très attaque peut survivre si ses attaquants sont faibles (cf. D attaque par C=0.230, garde 0.511)
5.5 Set Argumentation Frameworks (SetAF)
Les Set Argumentation Frameworks [Nielsen, Parsons, 2006] généralisent les attaques: c’est un ensemble d’arguments qui attaque collectivement un argument.
Attaque d’ensemble: \((X, a)\) où \(X\) est un ensemble non vide d’arguments et \(a\) est l’argument attaqué
Défense: Un argument \(a\) est défendu par \(E\) si pour chaque \(X\) qui attaque \(a\), un sous-ensemble de \(E\) attaque un élément de \(X\)
# --- 5.5 Set Argumentation Frameworks (SetAF) ---print("\n--- 5.5 Set Argumentation Frameworks (SetAF) ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Execution de l'exemple SetAF...") setaf_imports_ok =Falsetry:import jpypefrom jpype.types import*from java.util import HashSet, Set as JavaSetfrom org.tweetyproject.arg.setaf.syntax import SetAf, SetAttackfrom org.tweetyproject.arg.dung.syntax import Argumentfrom org.tweetyproject.arg.setaf.reasoners import SimpleGroundedSetAfReasoner, SimpleAdmissibleSetAfReasoner, SimplePreferredSetAfReasonerprint("Imports SetAF et dependances reussis.") setaf_imports_ok =Trueif setaf_imports_ok: set_af = SetAf() a = Argument("a"); b = Argument("b"); c = Argument("c"); d_arg = Argument("d") set_af.add(a); set_af.add(b); set_af.add(c); set_af.add(d_arg)# Créer les ensembles attaquants attacker_set1 = HashSet() attacker_set1.add(b); attacker_set1.add(d_arg) attacker_set2 = HashSet() attacker_set2.add(c); attacker_set2.add(a)# Ajouter les attaques d'ensemble set_attack1 = SetAttack(JObject(attacker_set1, JavaSet), a) set_attack2 = SetAttack(JObject(attacker_set2, JavaSet), c) set_af.add(set_attack1); set_af.add(set_attack2)print("\nFramework SetAF cree:")print(str(set_af))print(f" Arguments: {set_af.getNodes()}")print(f" Attaques Set: {set_af.getAttacks()}")print("\n--- Raisonnement SetAF ---")try: gr_setaf_reasoner = SimpleGroundedSetAfReasoner() gr_setaf_extension = gr_setaf_reasoner.getModel(set_af)print(f"\n* Extension Fondee (Grounded): {gr_setaf_extension}") adm_setaf_reasoner = SimpleAdmissibleSetAfReasoner() adm_setaf_extensions = adm_setaf_reasoner.getModels(set_af)print(f"\n* Extensions Admissibles ({adm_setaf_extensions.size()}): {adm_setaf_extensions}") pref_setaf_reasoner = SimplePreferredSetAfReasoner() pref_setaf_extensions = pref_setaf_reasoner.getModels(set_af)print(f"\n* Extensions Preferees ({pref_setaf_extensions.size()}): {pref_setaf_extensions}")except jpype.JException as e_reason_java: print(f"Erreur Java lors du raisonnement SetAF: {e_reason_java.message()}")exceptExceptionas e_reason_py: print(f"Erreur Python lors du raisonnement SetAF: {e_reason_py}")exceptImportErroras e: print(f"Erreur d'import pour SetAF : {e}. Verifiez le JAR 'arg.setaf'.")except jpype.JException as e_java: print(f"Erreur Java generale SetAF: {e_java.message()}")exceptExceptionas e_gen: print(f"Erreur Python inattendue SetAF: {e_gen}");import traceback; traceback.print_exc()
Arguments: {a, b, c, d}
Attaques collectives:
{b, d} --attaque--> a (b ET d ensemble attaquent a)
{a, c} --attaque--> c (a ET c ensemble attaquent c)
Différence avec Dung
Dans un framework de Dung classique, chaque attaque est binaire : x -> y. Dans SetAF, un ensemble d’arguments attaque collectivement : {x1, x2, ...} -> y.
L’attaque {b, d} -> a signifie que a est attaque uniquement si b ET d sont tous deux presents. Si un seul manque, l’attaque n’a pas lieu.
Analyse de l’extension Grounded : {b, c, d}
Argument
Statut
Raison
b
Accepte
Aucune attaque contre b
d
Accepte
Aucune attaque contre d
c
Accepte
L’attaque {a,c}->c necessite a, mais a est rejete
a
Rejete
Attaque par {b,d}, et b et d sont tous deux acceptes
Pourquoi a est rejete ?
L’attaque {b, d} -> a est activee car b et d sont dans l’extension
Pour defendre a, il faudrait attaquer b ou d
Aucun argument n’attaque b ou d, donc a ne peut pas etre defendu
Pourquoi c survit a l’attaque {a, c} -> c ?
L’attaque {a, c} -> c est paradoxale : elle necessite c pour attaquer c. Puisque a est rejete, l’ensemble {a, c} n’est jamais “complet” dans l’extension, donc l’attaque n’est pas activee.
Applications pratiques
Vote a l’unanimite : Une decision est bloquee seulement si TOUS les opposants votent contre
Systèmes de securite : Une alerte se declenche si TOUTES les conditions sont reunies
Consensus : Un argument est rejete seulement si un groupe entier s’y oppose
5.6 Frameworks Étendus (Attaques sur Attaques)
Les Frameworks d’Argumentation Étendus [Modgil, 2009] permettent de modéliser des scénarios où une attaque peut être attaquée par un argument. Cela représente des concepts comme la préférence entre attaques.
EAF (Extended AF): Arguments attaquent des attaques \((c, (a, b))\)
REAF (Récursive Extended AF): Généralise les EAF en permettant aux arguments d’attaquer des attaques sur des attaques (récursivement)
Recursivite en action : - Niveau 1 : c_r attaque (b_r, a_r) - Niveau 1 : e_r attaque (c_r, d_r) - Niveau 2 : f_r attaque (e_r, (c_r, d_r)) -> meta-meta-attaque
Application pratique : - EAF/REAF modelisent les debats sur la pertinence des arguments - “Je conteste que ton argument attaque le mien” (meta-argumentation) - Utile en droit, philosophie, et negociation
Exemple guide : Modelisation d’un debat avec un framework bipolaire
Contexte
Voici une modelisation guidee d’un debat sur le choix d’un langage de programmation. Etudiez la solution complete ci-dessous, puis traitez l’exercice qui suit.
Arguments : - a : “Python est facile a apprendre” - b : “Python est lent pour le calcul intensif” - c : “NumPy compense la lenteur de Python” (support de a, attaque b) - d : “Java a un typage statique plus sur” - e : “Le typage statique ralentit le développement” (attaque d) - f : “Les IDE modernes compensent le typage” (support de d, attaque e)
Relations : - Attaques : b attaque a, c attaque b, e attaque d, f attaque e - Supports : c supporte a, f supporte d
Objectifs
Construire un DungTheory avec les 6 arguments et les attaques
Calculer les extensions grounded et preferred
(Bonus) Si les imports bipolaires fonctionnent, construire un NecessityArgumentationFramework ou EvidentialArgumentationFramework avec les relations de support
Interpreter les résultats : quel langage “gagne” le debat ?
Indices :
DungTheory, Argument, Attack pour le framework de base
SimpleGroundedReasoner().getModel(theory) pour l’extension grounded
SimplePreferredReasoner().getModels(theory) pour les extensions preferred
Les supports bipolaires utilisent Support(source, target) et NecessityArgumentationFramework
# --- Exemple guide : Debat langage de programmation (Framework bipolaire) ---if jvm_ready:from org.tweetyproject.arg.dung.syntax import DungTheory, Argument, Attackfrom org.tweetyproject.arg.dung.reasoner import SimpleGroundedReasoner, SimplePreferredReasoner# 1. Creer les arguments a = Argument("a") # Python facile b = Argument("b") # Python lent c = Argument("c") # NumPy compense d = Argument("d") # Java typage sur e = Argument("e") # Typage ralentit f = Argument("f") # IDE compense# 2. Construire le framework theory = DungTheory()for arg in [a, b, c, d, e, f]: theory.add(arg) theory.add(Attack(b, a)) theory.add(Attack(c, b)) theory.add(Attack(e, d)) theory.add(Attack(f, e))print("Framework de Dung cree:")print(str(theory))# 3. Calculer les extensions grounded = SimpleGroundedReasoner().getModel(theory)print("\nExtension grounded:", grounded) preferred = SimplePreferredReasoner().getModels(theory)print("Extensions preferred:", preferred)# 4. Interpreter : quels arguments sont acceptes ? accepted =sorted(str(arg) for arg in grounded)print("\nArguments acceptes (grounded):", accepted) python_ok ="a"in accepted java_ok ="d"in acceptedprint(f" Python (a) accepte : {python_ok}")print(f" Java (d) accepte : {java_ok}")print("Conclusion: les deux langages 'gagnent', chaque critique etant neutralisee.")# 5. (Bonus) Relations de support avec un framework bipolaire (Necessity)try:from org.tweetyproject.arg.bipolar.syntax import ( NecessityArgumentationFramework, BArgument, BinaryAttack, BinarySupport )from org.tweetyproject.arg.bipolar.reasoner.necessity import ( GroundedReasoner as NecGroundedReasoner ) bargs = {name: BArgument(name) for name in"abcdef"} naf = NecessityArgumentationFramework()for arg in bargs.values(): naf.add(arg)for src, tgt in [("b", "a"), ("c", "b"), ("e", "d"), ("f", "e")]: naf.getAttacks().add(BinaryAttack(bargs[src], bargs[tgt]))for src, tgt in [("c", "a"), ("f", "d")]: naf.getSupports().add(BinarySupport(bargs[src], bargs[tgt]))print("\nBonus - Framework bipolaire (Necessity):")print(str(naf.prettyPrint()))print("Grounded (Necessity):", NecGroundedReasoner().getModels(naf))exceptExceptionas e_bonus:print(f"\nBonus non execute: {e_bonus}")else:print("ERREUR: JVM non demarree. Exemple guide (debat langage) non execute.")
Framework de Dung cree:
<{ a, b, c, d, e, f },[(c,b), (e,d), (b,a), (f,e)]>
Extension grounded: {a,c,d,f}
Extensions preferred: [{a,c,d,f}]
Arguments acceptes (grounded): ['a', 'c', 'd', 'f']
Python (a) accepte : True
Java (d) accepte : True
Conclusion: les deux langages 'gagnent', chaque critique etant neutralisee.
Bonus - Framework bipolaire (Necessity):
argument(a).
argument(b).
argument(c).
argument(d).
argument(e).
argument(f).
Grounded (Necessity): [{a,b,c,d,e,f}]
Exercice : Modelisation d’un debat avec un framework bipolaire
Contexte
A votre tour. Modelisez un debat sur le choix d’une architecture logicielle (monolithe vs microservices) :
Arguments suggeres : - m1 : “Le monolithe est simple a deployer” - m2 : “Le monolithe devient difficile a maintenir a grande echelle” - s1 : “Les microservices isolent les pannes” - s2 : “Les microservices ajoutent de la complexite reseau” - s3 : “Un bon outillage (Kubernetes) reduit la complexite reseau” (support de s1, attaque s2)
Objectifs
Construire un DungTheory avec vos arguments et des attaques coherentes
Calculer les extensions grounded et preferred
Interpreter : quelle architecture “gagne” selon votre modelisation ?
(Bonus) Ajouter les relations de support avec un framework bipolaire (Necessity / Evidential)
Indices :
Reprenez la structure de l’exemple guide ci-dessus
DungTheory, Argument, Attack pour le framework de base
SimpleGroundedReasoner().getModel(theory) et SimplePreferredReasoner().getModels(theory)
# --- Exercice : Debat architecture logicielle (Framework bipolaire) ---# TODO etudiant : modelisez le debat monolithe vs microservices# 1. Creer les arguments 2. Construire le DungTheory 3. Calculer les extensions# 4. Interpreter le resultat 5. (Bonus) ajouter les supports (framework bipolaire)print("Exercice a completer : voir l'exemple guide ci-dessus comme modele.")
Exercice a completer : voir l'exemple guide ci-dessus comme modele.
Exercice : Attaques collectives (SetAF)
La section 5.5 a introduit les SetAF : un ensemble d’arguments attaque collectivement une cible. L’attaque {x, y} -> z n’est active que si x ET y sont tous deux acceptes.
Contexte
Un comite de 3 membres (m1, m2, m3) peut bloquer une proposition prop, mais seulement s’ils s’opposent tous les trois ensemble : - Attaque collective : {m1, m2, m3} -> prop - temoin attaque m2 (un temoignage discredite m2)
Si m2 tombe, l’attaque collective contre prop n’est plus complete.
Indices :
set_af = SetAf(), puis SetAttack(JObject(attacker_set, JavaSet), cible)
SimpleGroundedSetAfReasoner().getModel(set_af) pour le grounded
# --- Exercice : Attaques collectives (SetAF) ---# TODO etudiant : modelisez une decision a l'unanimite avec un SetAF## Etape 1 : imports (cf section 5.5)# from org.tweetyproject.arg.setaf.syntax import SetAf, SetAttack# from org.tweetyproject.arg.dung.syntax import Argument# from org.tweetyproject.arg.setaf.reasoners import SimpleGroundedSetAfReasoner# from java.util import HashSet, Set as JavaSet# from jpype.types import JObject## Etape 2 : creer le SetAf et ajouter prop, m1, m2, m3, temoin# Etape 3 : construire {m1, m2, m3} (HashSet) et l'attaque collective -> prop# Etape 4 : ajouter temoin -> m2 et calculer le grounded# Etape 5 (bonus) : retirer temoin -> m2 et re-calculerifnot jvm_ready:print("ERREUR: JVM non demarree.")else: set_af =None# TODO etudiant : remplacer par le SetAf construit extension =None# TODO etudiant : remplacer par SimpleGroundedSetAfReasoner().getModel(set_af)print("Exercice a completer")
Le notebook jumeau Tweety-07a-Extended-Frameworks-CSharp.ipynb couvre les memes frameworks que ce notebook-ci, mais selon une architecture fondamentalement differente au depart (tranche 1, from-scratch), puis selon une architecture a nouveau differente depuis la tranche 2 (lib-vs-lib via IKVM). Les chiffres ci-dessous sont ancres sur les cellules qui les mesurent : ils peuvent etre re-verifies par les commandes en fin de note ; cette note ne tient pas en l’air.
Aspect
Python (ce notebook)
C# jumeau (tranche 1)
C# jumeau (tranche 2)
Moteur
JVM Tweety via jpype (42 JARs charges, init_tweety())
Frameworks uniquement Python (Tweety ecosystem) : Evidential BAF (5.2a), Necessity BAF (5.2b), WAF (5.3, semiring pondere), SAF (5.4, votes + ISS), REAF (5.6 niveau 2 recursif). Ces frameworks n’ont pas de pendant C# : ni en tranche 1 (from-scratch) ni en tranche 2 (le shade ne les contient pas).
Frameworks uniquement C# tranche 1 : VAF (Value-based AF, Bench-Capon) avec ordre de preference entre valeurs (Economie > Environnement -> grounded {a} ; inverse -> grounded {a,b}). La tranche 2 n’a pas re-sonde VAF (cell 39 limite la sonde a ADF/SetAF/EAF/Bipolar) – l’asymetrie Python / C# est preservee sur ce framework.
Python notebook montre l’usage de l’ecosysteme Tweety complet (dependance lourde mais riche : 7 frameworks ADF+Evidential+Necessity+WAF+SAF+SetAF+EAF/REAF, solveurs SAT natifs via JNI).
C# jumeau tranche 1 montre qu’on peut implementer le substrat mathematique sans JVM (Kleene 3-valued, ADF fixed-point, SetAF labelling, EAF reinstatement, VAF value-pref) en pure BCL .NET 9 – pedagogie de l’implementation, pas de l’usage.
C# jumeau tranche 2 montre la lib-vs-lib : refaire un calcul qu’on sait faire from-scratch, mais cette fois en utilisant la librairie Java via IKVM. Pedagogie de la verification croisee (memes donnees, deux implementations) et de la frontiere de types (cell 23 : JObject + casts explicites, pas de marshalling magique).
Asymetrie reelle (mesuree, pas presupposee) : sur SetAF, EAF, Bipolar, le shade IKVM rend 0 type (cell 41). La tranche 2 ne peut donc PAS remplacer le jumeau tranche 1 sur ces trois frameworks ; la tranche 1 reste l’autorite pedagogique pour SetAF et EAF. Inversement, la tranche 1 n’a pas porte Bipolar du tout – il n’y a pas de parite Python/C# sur ce framework, juste un usage Python.
Exemples guides des deux notebooks utilisent des shapes differents (Python EAF = {b_e,e_e,d_e} 1 ext sur 5 args ; C# EAF = {a,b,c} 3 args avec reinstatement explicite) – la parite est sur l’algorithme (Kleene 3-valued + grounded fixed-point), pas sur l’exemple exact.
Ancrage prose <-> output (cette note ne tient pas en l’air) : les chiffres ci-dessus peuvent etre re-verifies par les commandes shell suivantes, executees a la racine du depot :
# Comptes cellules : Python notebookpython-c"import json; nb=json.load(open('MyIA.AI.Notebooks/SymbolicAI/Tweety/Tweety-07a-Extended-Frameworks-Python.ipynb',encoding='utf-8')); print('Python total', len(nb['cells']), 'code', sum(1 for c in nb['cells'] if c['cell_type']=='code'))"# Comptes cellules : C# jumeaupython-c"import json; nb=json.load(open('MyIA.AI.Notebooks/SymbolicAI/Tweety/Tweety-07a-Extended-Frameworks-CSharp.ipynb',encoding='utf-8')); print('C# total', len(nb['cells']), 'code', sum(1 for c in nb['cells'] if c['cell_type']=='code'))"# Tranche 2 IKVM : lister les cellules qui chargent le shade via IKVMgrep-lE'IKVM|tweety-7a\.dll' MyIA.AI.Notebooks/SymbolicAI/Tweety/Tweety-07a-Extended-Frameworks-CSharp.ipynb# Asymetrie SetAF/EAF/Bipolar : la sonde 7.7.3 (cell 39) + lecture 7.7.4 (cell 41)grep-nE'absent|0 type' MyIA.AI.Notebooks/SymbolicAI/Tweety/Tweety-07a-Extended-Frameworks-CSharp.ipynb
Ces commandes sont idempotentes : les relancer ne modifie rien et reproduit les memes chiffres tant que les notebooks sources ne bougent pas. Si l’un des chiffres devient faux apres une evolution, c’est cette note qu’il faut re-actualiser (pas re-livrer un nombre fige).