Note: ASP necessite Clingo installe. Le notebook configure automatiquement le chemin si Clingo est disponible.
Note de parité cross-langage : ce notebook est le jumeau Python de Tweety-06-Structured-Argumentation-CSharp.ipynb (twin C# from-scratch BCL .NET, 0 JVM). Pour les concepts partagés (ASPIC+, DeLP, ABA, Argumentation Déductive, ASP), voir la cellule d’introduction ; le twin C# reconstruit les concepts (pas l’API JVM) pour rester exécutable end-to-end sur toute machine .NET 9+. Marathon parité .NET ⇄ Python : EPIC #4956.
# --- Initialisation JVM Tweety + Outils Externes ---print("--- Verification JVM Tweety + Outils ---")jvm_ready =Falseimport jpypeimport jpype.importsimport osimport pathlibimport shutilimport platform# === Configuration COMPLETE des outils externes ===EXTERNAL_TOOLS = {"CLINGO": "","SPASS": "","EPROVER": "","SAT_SOLVER_PYTHON": "","MARCO": "",}def get_tool_path(tool_name):"""Retourne le chemin valide d'un outil ou None.""" path_str = EXTERNAL_TOOLS.get(tool_name, "")ifnot path_str:returnNoneif shutil.which(path_str):return path_str path_obj = pathlib.Path(path_str)if path_obj.is_file():returnstr(path_obj.resolve())if path_obj.is_dir():returnstr(path_obj.resolve())returnNone# --- Auto-detection des outils ---system = platform.system()exe_suffix =".exe"if system =="Windows"else""# 1. Clingo (ASP solver) - Tweety attend le REPERTOIREfor cp in [shutil.which("clingo"), pathlib.Path(f"ext_tools/clingo/clingo{exe_suffix}"), pathlib.Path(f"../ext_tools/clingo/clingo{exe_suffix}")]:if cp and (isinstance(cp, str) or cp.exists()): parent = pathlib.Path(cp).parent ifisinstance(cp, str) else cp.parent EXTERNAL_TOOLS["CLINGO"] =str(parent.resolve())break# 2. SPASS (Modal logic prover)for sp in [shutil.which("SPASS"), pathlib.Path(f"ext_tools/spass/SPASS{exe_suffix}"), pathlib.Path(f"../ext_tools/spass/SPASS{exe_suffix}")]:if sp and (isinstance(sp, str) or sp.exists()): EXTERNAL_TOOLS["SPASS"] =str(pathlib.Path(sp).resolve()) ifisinstance(sp, pathlib.Path) else spbreak# 3. EProver (FOL theorem prover)for ep in [shutil.which("eprover"), pathlib.Path(f"../ext_tools/EProver/eprover{exe_suffix}"), pathlib.Path(f"ext_tools/EProver/eprover{exe_suffix}")]:if ep: ep_path = pathlib.Path(ep) ifisinstance(ep, str) else epif ep_path.exists(): EXTERNAL_TOOLS["EPROVER"] =str(ep_path.resolve())break# 4. SAT Solver Python (CaDiCaL, Glucose via pySAT)for sat in [pathlib.Path("../ext_tools/sat_solver.py"), pathlib.Path("ext_tools/sat_solver.py")]:if sat.exists(): EXTERNAL_TOOLS["SAT_SOLVER_PYTHON"] =str(sat.resolve())break# 5. MARCO (MUS enumerator avec Z3)for mp in [pathlib.Path("../ext_tools/marco.py"), pathlib.Path("ext_tools/marco.py")]:if mp.exists(): EXTERNAL_TOOLS["MARCO"] =str(mp.resolve())break# === Initialisation JVM ===if jpype.isJVMStarted():print("JVM deja en cours d'execution.") jvm_ready =Trueelse: jdk_portable =Nonefor jdk_path in [pathlib.Path("jdk-17-portable"), pathlib.Path("../Argument_Analysis/jdk-17-portable")]:if jdk_path.exists(): zulu_dirs =list(jdk_path.glob("zulu*"))if zulu_dirs: jdk_portable = zulu_dirs[0] os.environ["JAVA_HOME"] =str(jdk_portable.resolve())print(f"JDK portable: {jdk_portable.name}")breakifnot os.environ.get("JAVA_HOME"):print("ERREUR: JAVA_HOME non defini et JDK portable non trouve.")else: LIB_DIR = pathlib.Path("libs")ifnot LIB_DIR.exists(): LIB_DIR = pathlib.Path("../Argument_Analysis/libs")if LIB_DIR.exists(): jar_files =list(LIB_DIR.glob("*.jar"))if jar_files: classpath = os.pathsep.join(str(j.resolve()) for j in jar_files)try: jpype.startJVM(classpath=[classpath])print(f"JVM demarree avec {len(jar_files)} JARs.") jvm_ready =TrueexceptExceptionas e:print(f"Erreur demarrage JVM: {e}")# === Resume des outils ===if jvm_ready:print("\n--- Outils disponibles ---")for tool, path in EXTERNAL_TOOLS.items():if path: short_path = path.split(os.sep)[-1] iflen(path) >30else pathprint(f" {tool}: {short_path}")print(f"\nJVM prete. Outils: {sum(1for t,p in EXTERNAL_TOOLS.items() if p)}/{len(EXTERNAL_TOOLS)}")
ASPIC+ est un framework mature et largement utilisé pour l’argumentation structurée.
Origine. ASPIC+ est formalisé par Modgil, S. & Prakken, H. (2014), The ASPIC+ framework for structured argumentation: a tutorial, Argument & Computation 5(1):31-62 — qui refactorise et stabilise les versions antérieures (Prakken 2010) en un framework de référence distinguant règles strictes/défaisables, axiomes ordinaires/présumés, et trois types de conflit (rebutting, undercutting, undermining). La conversion vers les cadres de Dung se fait via la relation d’attaque dérivée des conflits entre arguments structurés. Contrairement à Dung où les arguments sont abstraits, ASPIC+ construit des arguments logiques à partir d’une base de connaissances et de règles d’inférence, en distinguant règles strictes et règles défaisables.
Base de Connaissances (KB): Contient des axiomes (faits certains) et des règles.
Règles d’inférence:
Strictes (StrictInferenceRule, ->): Si les prémisses sont acceptées, la conclusion l’est nécessairement.
Défaisables (DefeasibleInferenceRule, =>): Si les prémisses sont acceptées, la conclusion l’est plausiblement, mais la règle elle-même peut être attaquée (undercutting) ou la conclusion réfutée (rebutting).
Préférences: Un ordre (souvent partiel) peut être défini sur les règles défaisables pour résoudre les attaques “rebutting”.
Arguments: Construits par chaînage de règles depuis les axiomes.
Attaques: ASPIC+ définit trois types d’attaque selon leur cible (Prakken 2010) : (i) rebuttal — la conclusion de l’argument attaqué, y compris la conclusion intermédiaire d’un sous-argument (elle-même réfutable) ; (ii) undermining — une prémisse ordinaire (un fait à la base de l’argument, et non une conclusion) ; (iii) undercutting — l’application d’une règle défaisable (le lien d’inférence lui-même, indépendamment de ses prémisses ou de sa conclusion). Viser une « sous-conclusion » intermédiaire est donc un rebuttal du sous-argument, et non un undermining.
AspicArgumentationTheory: Représente la théorie ASPIC+. Nécessite un RuleFormulaGenerator pour spécifier la logique sous-jacente (ex: PlFormulaGenerator pour la logique propositionnelle).
Conversion vers Dung (asDungTheory): Permet d’analyser la théorie ASPIC+ en la transformant en un AAF standard, sur lequel on peut appliquer les sémantiques de Dung (Grounded, Preferred, etc.).
L’exemple suivant utilise la logique propositionnelle comme langage sous-jacent, basé sur AspicExample.java.
# --- 4.2.1 ASPIC+ : Construction et Conversion en Dung (PL) ---print("\n--- 4.2.1 ASPIC+ : Construction et Conversion en Dung (PL) ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Execution de l'exemple ASPIC+...")try:import jpypefrom jpype.types import*from org.tweetyproject.logics.pl.syntax import Proposition, Negation, PlFormulafrom org.tweetyproject.arg.aspic.syntax import AspicArgumentationTheory, DefeasibleInferenceRule, StrictInferenceRulefrom org.tweetyproject.arg.aspic.ruleformulagenerator import PlFormulaGeneratorfrom org.tweetyproject.arg.dung.syntax import Argument as DungArgument, Attack as DungAttack, DungTheoryfrom org.tweetyproject.arg.dung.reasoner import SimpleGroundedReasonerprint("OK: Imports ASPIC+ (PL) et Dung reussis.")# --- Theorie ASPIC+ --- pl_formula_generator = PlFormulaGenerator() aspic_theory = AspicArgumentationTheory(pl_formula_generator) aspic_theory.setRuleFormulaGenerator(pl_formula_generator)# Propositions a = Proposition("a"); b = Proposition("b"); c = Proposition("c"); d_prop = Proposition("d")# Regles Defaisables (=>)# r1: b, c => a r1_def = DefeasibleInferenceRule() r1_def.setConclusion(a) r1_def.addPremise(b); r1_def.addPremise(c) aspic_theory.addRule(r1_def)# r2: b => d r2_def = DefeasibleInferenceRule() r2_def.setConclusion(d_prop) r2_def.addPremise(b) aspic_theory.addRule(r2_def)# r3: a => !d r3_def = DefeasibleInferenceRule() r3_def.setConclusion(Negation(d_prop)) r3_def.addPremise(a) aspic_theory.addRule(r3_def)# Axiomes (faits certains) aspic_theory.addAxiom(b) aspic_theory.addAxiom(c)print("\n--- Theorie ASPIC+ ---")print(str(aspic_theory))# --- Conversion en Cadre de Dung ---print("\n--- Conversion en AF de Dung ---")try: dung_equivalent = aspic_theory.asDungTheory()print("Arguments generes par ASPIC+:") args_aspic = dung_equivalent.getNodes()if args_aspic.isEmpty():print(" (Aucun argument genere)")else:for arg in args_aspic:print(f" - {arg}")print("\nAttaques generees par ASPIC+:") attacks_aspic = dung_equivalent.getAttacks()if attacks_aspic.isEmpty():print(" (Aucune attaque generee)")else:for att in attacks_aspic:print(f" - {att}")# --- Raisonnement sur l'AF equivalent ---print("\nRaisonnement sur l'AF de Dung equivalent:") grounded_reasoner_dung = SimpleGroundedReasoner() grounded_extension = grounded_reasoner_dung.getModel(dung_equivalent)print(f" - Extension Grounded : {grounded_extension}")except jpype.JException as e_conv_java:print(f"Erreur Java lors de la conversion ASPIC->Dung: {e_conv_java.message()}")exceptExceptionas e_conv_py:print(f"Erreur Python lors de la conversion ASPIC->Dung: {e_conv_py}")exceptImportErroras e:print(f"Erreur d'import pour ASPIC+ : {e}. Verifiez le JAR 'arg.aspic'.")except jpype.JException as e_java:print(f"Erreur Java generale dans l'exemple ASPIC+: {e_java.message()}")exceptExceptionas e_gen:print(f"Erreur Python inattendue dans l'exemple ASPIC+: {e_gen}")import traceback traceback.print_exc()
--- 4.2.1 ASPIC+ : Construction et Conversion en Dung (PL) ---
JVM prete. Execution de l'exemple ASPIC+...
OK: Imports ASPIC+ (PL) et Dung reussis.
--- Theorie ASPIC+ ---
ArgumentationSystem [rules=[ -> c, -> b, b, c => a, b => d, a => !d]]
--- Conversion en AF de Dung ---
Arguments generes par ASPIC+:
- b => d [ -> b]
- -> b
- -> c
- b, c => a [ -> b, -> c]
- a => !d [b, c => a [ -> b, -> c]]
Attaques generees par ASPIC+:
- (b => d [ -> b],a => !d [b, c => a [ -> b, -> c]])
- (a => !d [b, c => a [ -> b, -> c]],b => d [ -> b])
Raisonnement sur l'AF de Dung equivalent:
- Extension Grounded : { -> b, -> c,b, c => a [ -> b, -> c]}
Interpretation des résultats ASPIC+
L’exemple construit une théorie ASPIC+ avec conflit entre conclusions opposees.
Structure du problème :
Faits (axiomes): b, c (certains)
Règles defaisables: r1: b, c => a
r2: b => d
r3: a => !d
Arguments generes :
Argument
Structure
Conclusion
Arg1
-> b
b (axiome)
Arg2
-> c
c (axiome)
Arg3
b, c => a [-> b, -> c]
a (derive de b et c)
Arg4
b => d [-> b]
d (derive de b)
Arg5
a => !d [Arg3]
!d (derive de a)
Attaques (rebuttals) : - Arg4 attaque Arg5 : d vs !d (conclusions contradictoires) - Arg5 attaque Arg4 : !d vs d
Extension Grounded : {-> b, -> c, b, c => a}
Les axiomes b et c sont acceptes, ainsi que l’argument pour a. Les arguments pour d et !d s’annulent mutuellement (aucun n’est dans l’extension grounded).
Point cle ASPIC+ : La conversion vers Dung permet d’appliquer toutes les sémantiques classiques (Grounded, Preferred, Stable) sur des arguments structures.
Exercice : Debat contradictoire avec ASPIC+
La section 4.2 a montre comment ASPIC+ convertit une théorie structuree en cadre de Dung. Construisez votre propre théorie ASPIC+ pour modeliser un debat contradictoire sur l’approbation d’un projet.
Contexte
Un comite doit decider si un projet doit etre approuve ou rejete :
Le conflit : si risque_eleve etait aussi un axiome, les arguments pour approuver et rejeter s’attaqueraient mutuellement.
Objectifs
Construire une théorie AspicArgumentationTheory avec les 3 règles et 2 axiomes
Convertir en AF de Dung avec asDungTheory()
Calculer l’extension grounded avec SimpleGroundedReasoner
Interpreter : quels arguments sont acceptes ?
Bonus
Ajoutez risque_eleve comme axiome supplementaire et observez comment le conflit modifie l’extension grounded. Comparez avec l’exemple de la section 4.2.1 ou d et !d s’annulent mutuellement.
# --- Exercice : Debat contradictoire avec ASPIC+ ---# TODO etudiant : construisez une theorie ASPIC+ et analysez les conflits## Etape 1 : importer les classes ASPIC+ (cf section 4.2.1)# from org.tweetyproject.arg.aspic.syntax import AspicArgumentationTheory, DefeasibleInferenceRule# from org.tweetyproject.arg.aspic.ruleformulagenerator import PlFormulaGenerator# from org.tweetyproject.logics.pl.syntax import Proposition, Negation# from org.tweetyproject.arg.dung.reasoner import SimpleGroundedReasoner## Etape 2 : creer la theorie ASPIC+ avec PlFormulaGenerator# Etape 3 : definir les propositions (budget_disponible, equipe_prete, risque_eleve, approuver, rejeter)# Etape 4 : ajouter les 3 regles defaisables et les 2 axiomes# r1: budget_disponible, equipe_prete => approuver# r2: risque_eleve => rejeter# r3: approuver => !rejeter# Axiomes: budget_disponible, equipe_prete# Etape 5 : convertir en Dung avec asDungTheory() et calculer l'extension grounded# Etape 6 : afficher les arguments, attaques et extension## Indice : la regle r3 utilise Negation(Proposition("rejeter")) comme conclusion# Indice : sans risque_eleve comme axiome, l'extension grounded contient approuver# Indice : ajoutez risque_eleve comme axiome supplementaire (bonus) pour observer le conflitifnot jvm_ready:print("ERREUR: JVM non demarree.")else: aspic_theory_ex =None# TODO etudiant : remplacer par la theorie ASPIC+ construite grounded_ext =None# TODO etudiant : remplacer par l'extension groundedprint("Exercice a completer")
Exercice a completer
4.3 Defeasible Logic Programming (DeLP)
Transition depuis ASPIC+ :
Origine. DeLP (Defeasible Logic Programming) est introduit par García, A. J. & Simari, G. R. (2004), Defeasible logic programming: an argumentative approach, Theory and Practice of Logic Programming 4(1+2):95-138 — un langage de programmation logique où les règles défaisables (préfixées par <= dans la littérature, < côté programme) engendrent des arguments, et la sémantique est dialectique : une requête est warranted (yes), defeated (no) ou undecided selon la construction d’un arbre dialectique tranché par la spécificité généralisée.
Après ASPIC+ qui se convertit en Dung et utilise des sémantiques ensemblistes (Grounded, Preferred, Stable), nous explorons un paradigme différent : Defeasible Logic Programming.
Différences clés entre ASPIC+ et DeLP :
Aspect
ASPIC+
DeLP
Sémantique
Extensions d’arguments (Dung)
Warrant (justification dialectique)
Comparaison d’arguments
Ordre explicite sur règles/conclusions
Spécificité généralisée (implicite)
Output
Extensions (ensembles d’arguments)
YES / NO / UNDECIDED (par requête)
Style
Déclaratif (KB + règles)
Programmation logique
Qu’est-ce que DeLP ?
DeLP combine la programmation logique avec le raisonnement défaisable. Il utilise : - Règles strictes (<-) : Conclusions certaines si prémisses vraies - Règles défaisables (-<) : Conclusions plausibles mais réfutables
Un argument est construit pour supporter un littéral, et la notion de “warrant” (justification) est déterminée en comparant les arguments pour et contre ce littéral.
Spécificité généralisée :
Le critère clé de DeLP pour trancher entre arguments conflictuels : - Une règle r1 est plus spécifique que r2 si toute situation satisfaisant r1 satisfait aussi r2, mais pas l’inverse - Exemple : !Fly(X) -< Penguin(X) est plus spécifique que Fly(X) -< Bird(X) - Car tout Penguin est un Bird (mais pas l’inverse) - Donc la règle “Penguin” l’emporte sur la règle “Bird”
Avantage de DeLP :
Raisonnement plus intuitif pour des domaines où les exceptions sont hiérarchisées naturellement (droit, médecine, sens commun).
# --- 4.3 Defeasible Logic Programming (DeLP) ---print("\n--- 4.3 Defeasible Logic Programming (DeLP) ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Execution de l'exemple DeLP...")try:# Importsimport jpypefrom jpype.types import*import pathlibfrom java.io import StringReaderfrom java.util import ArrayList# Imports DeLPfrom org.tweetyproject.arg.delp.parser import DelpParserfrom org.tweetyproject.arg.delp.reasoner import DelpReasonerfrom org.tweetyproject.arg.delp.semantics import GeneralizedSpecificityfrom org.tweetyproject.arg.delp.syntax import DefeasibleLogicProgram# Imports FOL/Commons necessairesfrom org.tweetyproject.logics.fol.syntax import FolFormula, FolSignature, FolAtomfrom org.tweetyproject.logics.commons.syntax import Constant, Predicateprint("Imports DeLP, FOL et Commons necessaires reussis.")# --- Parsing du programme DeLP --- delp_filename ="birds2.txt" delp_filepath = pathlib.Path("resources") / delp_filename delp_program =None parser_delp = DelpParser()ifnot delp_filepath.is_file():print(f"ERREUR: Fichier DeLP requis '{delp_filepath}' non trouve !")print(" Utilisation d'un exemple integre (birds.txt simplifie).") birds_program_str =""" Bird(X) <- Chicken(X). Bird(X) <- Penguin(X). ~Fly(X) <- Penguin(X). Chicken(tina). Penguin(tweety). Scared(tina). Fly(X) -< Bird(X). ~Fly(X) -< Chicken(X). Fly(X) -< Chicken(X), Scared(X). """try: string_reader = StringReader(birds_program_str) delp_program = parser_delp.parseBeliefBase(string_reader); string_reader.close()print("Programme charge avec succes depuis la chaine integree.")exceptExceptionas e_str: print(f"Erreur parsing chaine integree: {e_str}"); delp_program =Noneelse:print(f"\nChargement du programme DeLP depuis: {delp_filepath}")try: delp_program = parser_delp.parseBeliefBaseFromFile(str(delp_filepath))print("Programme charge avec succes depuis le fichier.")exceptExceptionas e_file: print(f"Erreur chargement fichier: {e_file}"); delp_program =None# --- Raisonnement DeLP ---if delp_program isnotNone:print("\nProgramme DeLP charge:\n", str(delp_program))# DEBUG Signature sig_delp =Nonetry: sig_delp = delp_program.getSignature()print("\nSignature extraite par DelpParser:")print(sig_delp)ifhasattr(sig_delp, 'getPredicates'): print("Predicates:", sig_delp.getPredicates())ifhasattr(sig_delp, 'getConstants'): print("Constants:", sig_delp.getConstants())exceptExceptionas e_sig: print(f"Erreur recuperation/affichage signature: {e_sig}")# Construction programmatique des requetes# IMPORTANT: Utiliser les predicats et constantes du programme charge!# Le fichier birds2.txt utilise: Fly (pas Flies), Bird, Penguin, Wings# Constantes: tweety, opusprint("\nConstruction programmatique des requetes FOL...") queries_fol_obj = {}try:# Predicats et constantes correspondant au programme birds2.txt Fly = Predicate("Fly", 1) # PAS "Flies" ! Bird = Predicate("Bird", 1) tweety = Constant("tweety") opus = Constant("opus")# Construire les FolAtom args_tweety = ArrayList([tweety]) args_opus = ArrayList([opus])# Requetes sur les predicats qui existent dans le programme queries_fol_obj["Fly(tweety)"] = FolAtom(Fly, JObject(args_tweety, "java.util.List")) queries_fol_obj["Fly(opus)"] = FolAtom(Fly, JObject(args_opus, "java.util.List")) queries_fol_obj["Bird(tweety)"] = FolAtom(Bird, JObject(args_tweety, "java.util.List")) queries_fol_obj["Bird(opus)"] = FolAtom(Bird, JObject(args_opus, "java.util.List"))print("Requetes construites programmatiquement.")exceptExceptionas e_build:print(f"Erreur lors de la construction programmatique des requetes: {e_build}") queries_fol_obj =Noneif queries_fol_obj: reasoner_delp = DelpReasoner(GeneralizedSpecificity()) FolFormula_class = jpype.JClass("org.tweetyproject.logics.fol.syntax.FolFormula")print("\nEvaluation des requetes DeLP:")print("(YES=justifie, NO=refute, UNDECIDED=indetermine)")for q_str, query_formula_obj in queries_fol_obj.items():print(f" Querying '{q_str}'...", end="")try: result_delp = reasoner_delp.query(delp_program, JObject(query_formula_obj, FolFormula_class))print(f" Resultat: {result_delp}")except jpype.JException as e_query_java:print(f" ERREUR JAVA: {e_query_java.message()}")exceptExceptionas e_query_py:print(f" ERREUR PYTHON: {e_query_py}")# Explication des resultats attendus pour birds2.txt:# - tweety est un Penguin donc Bird(tweety)=YES mais Fly(tweety)=NO (les pingouins ne volent pas)# - opus est un Bird mais pas de regle defaisable pour Fly(opus) -> UNDECIDED ou NOprint("\nNote: Fly(tweety)=NO car ~Fly(X) -< Penguin(X) l'emporte sur Fly(X) -< Bird(X)")else:print("\nConstruction des requetes echouee, raisonnement saute.")else:print("\nAucun programme DeLP charge ou erreur de chargement, raisonnement saute.")exceptImportErroras e: print(f"Erreur d'import pour DeLP/Commons/FOL : {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()
--- 4.3 Defeasible Logic Programming (DeLP) ---
JVM prete. Execution de l'exemple DeLP...
Imports DeLP, FOL et Commons necessaires reussis.
Chargement du programme DeLP depuis: resources\birds2.txt
Programme charge avec succes depuis le fichier.
Programme DeLP charge:
Wings(tweety).
Fly(X) -< Bird(X).
Penguin(tweety).
Bird(X) <- Penguin(X).
!Fly(X) -< Penguin(X).
Bird(opus).
Signature extraite par DelpParser:
[Thing = {tweety, opus}], [Bird(Thing), Penguin(Thing), Wings(Thing), Fly(Thing)], []
Predicates: [Bird(Thing), Penguin(Thing), Wings(Thing), Fly(Thing)]
Constants: [tweety, opus]
Construction programmatique des requetes FOL...
Requetes construites programmatiquement.
Evaluation des requetes DeLP:
(YES=justifie, NO=refute, UNDECIDED=indetermine)
Querying 'Fly(tweety)'... Resultat: The answer is: NO
Querying 'Fly(opus)'... Resultat: The answer is: YES
Querying 'Bird(tweety)'... Resultat: The answer is: YES
Querying 'Bird(opus)'... Resultat: The answer is: YES
Note: Fly(tweety)=NO car ~Fly(X) -< Penguin(X) l'emporte sur Fly(X) -< Bird(X)
Interpretation des résultats DeLP
Le raisonnement defaisable DeLP produit des reponses basees sur la specificite generalisee :
Résultats des requêtes :
Requête
Résultat
Explication
Fly(tweety)
NO
Refute car tweety est un Penguin
Fly(opus)
YES
Justifie car opus est un Bird sans exception
Bird(tweety)
YES
Derive de Bird(X) <- Penguin(X)
Bird(opus)
YES
Fait explicite dans le programme
Mécanisme de la specificite generalisee :
Pour Fly(tweety) : 1. Règle defaisable Fly(X) -< Bird(X) s’applique (tweety est un Bird via Penguin) 2. Règle defaisable !Fly(X) -< Penguin(X) s’applique aussi (tweety est un Penguin) 3. La règle “Penguin” est plus spécifique que “Bird” (tout Penguin est un Bird, pas l’inverse) 4. Donc !Fly(tweety) l’emporte -> reponse NO
Pour Fly(opus) : 1. Seule Fly(X) -< Bird(X) s’applique (opus n’est pas un Penguin) 2. Pas de contre-argument -> reponse YES
Différence avec ASPIC+ : - DeLP utilise la specificite pour comparer arguments - ASPIC+ utilise un ordre explicite sur les règles ou les conclusions
4.4 Assumption-Based Argumentation (ABA)
Transition depuis DeLP :
Après DeLP (règles défaisables + spécificité), nous explorons une approche conceptuellement différente : Assumption-Based Argumentation.
Spécificités d’ABA par rapport à ASPIC+ et DeLP :
Concept
ASPIC+ / DeLP
ABA
Briques de base
Règles strictes/défaisables
Hypothèses (assumptions)
Mécanisme d’attaque
Conclusion vs conclusion/règle
Conclusion vs contraire d’hypothèse
Structure des arguments
Chaînage de règles depuis faits
Dérivation logique depuis hypothèses
Approche
Bottom-up (des faits vers conclusions)
Top-down (des hypothèses vers conclusions)
Qu’est-ce qu’ABA ?
En ABA, certains littéraux sont désignés comme des hypothèses (assumptions). Les arguments sont dérivés en utilisant des règles logiques (similaires à ASPIC+) à partir de ces hypothèses.
Mécanisme d’attaque clé : Une attaque d’un argument vers un autre se produit si la conclusion du premier est le contraire d’une hypothèse utilisée dans le second.
Composants d’une théorie ABA :
AbaTheory: Contient les règles, l’ensemble des hypothèses, et la définition des contraires
Logique sous-jacente: Peut être PL (logique propositionnelle) ou FOL (logique du premier ordre)
Raisonnement: Basé sur la conversion en AF de Dung (FlatAbaReasoner, PreferredReasoner)
Motivation pour ABA :
ABA est particulièrement adapté aux problèmes où on doit tester des hypothèses concurrentes : - Diagnostic médical : Hypothèses = maladies possibles, contraires = symptômes incompatibles - Configuration de systèmes : Hypothèses = choix de composants, contraires = incompatibilités - Raisonnement scientifique : Hypothèses = théories explicatives, contraires = observations contradictoires
Un argument pour “grippe” attaque un argument utilisant l’hypothèse “non_grippe”.
# --- 4.4 Assumption-Based Argumentation (ABA) ---print("\n--- 4.4 Assumption-Based Argumentation (ABA) ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Execution de l'exemple ABA...")try:import jpype;from jpype.types import*;import pathlib;from java.io import StringReaderfrom org.tweetyproject.arg.aba.parser import AbaParserfrom org.tweetyproject.arg.aba.syntax import AbaTheory, Assumptionfrom org.tweetyproject.logics.pl.parser import PlParserfrom org.tweetyproject.logics.pl.syntax import Proposition, PlFormulafrom org.tweetyproject.logics.fol.parser import FolParserfrom org.tweetyproject.logics.fol.syntax import FolFormula, FolSignaturefrom org.tweetyproject.logics.pl.sat import SatSolver, Sat4jSolverfrom org.tweetyproject.arg.aba.reasoner import FlatAbaReasoner, PreferredReasonerfrom org.tweetyproject.arg.dung.semantics import Semanticsfrom org.tweetyproject.arg.dung.syntax import DungTheoryprint("OK: Imports ABA et dependances reussis.")# --- Exemple 1: Propositional Logic (PL) ---print("\n--- Exemple ABA avec Logique Propositionnelle ---") SatSolver.setDefaultSolver(Sat4jSolver()) pl_parser_for_aba = PlParser() aba_parser_pl = AbaParser(pl_parser_for_aba) aba_pl_filename ="example2.aba" aba_pl_filepath = pathlib.Path("resources") / aba_pl_filename aba_theory_pl =Noneifnot aba_pl_filepath.is_file():print(f"ERREUR: Fichier ABA (PL) requis '{aba_pl_filepath}' non trouve !")else:print(f"Chargement ABA (PL) depuis fichier: {aba_pl_filepath}")try: aba_theory_pl = aba_parser_pl.parseBeliefBaseFromFile(str(aba_pl_filepath))print("OK: Theorie ABA (PL) chargee depuis fichier.")exceptExceptionas e_fpl: print(f"Erreur chargement fichier ABA (PL): {e_fpl}")if aba_theory_pl isnotNone:print("\nTheorie ABA (PL):", str(aba_theory_pl)) reasoner_flat_pref = FlatAbaReasoner(Semantics.PREFERRED_SEMANTICS) reasoner_pref_aba = PreferredReasoner() assumption_pl = Assumption(Proposition("a"))print("\nRequetes sur la theorie ABA (PL):")print(f" - Query '{assumption_pl}' (Flat Preferred)? {reasoner_flat_pref.query(aba_theory_pl, assumption_pl)}")print(f" - Query '{assumption_pl}' (ABA Preferred)? {reasoner_pref_aba.query(aba_theory_pl, assumption_pl)}")# --- Exemple 2: First-Order Logic (FOL) ---print("\n\n--- Exemple ABA avec Logique du Premier Ordre ---") aba_fol_filename ="smp_fol.aba" aba_fol_filepath = pathlib.Path("resources") / aba_fol_filename aba_theory_fol =Noneifnot aba_fol_filepath.is_file():print(f"ERREUR: Fichier ABA (FOL) requis '{aba_fol_filepath}' non trouve !")else: fol_parser_for_aba = FolParser() sig_fol_str =""" Male = {a, b} Female = {c, d} type(Pair(Male, Female)) type(ContraryPair(Male, Female)) type(MPrefers(Male, Female, Female)) type(WPrefers(Female, Male, Male)) """try: sig_fol_aba = fol_parser_for_aba.parseSignature(sig_fol_str) fol_parser_for_aba.setSignature(sig_fol_aba)print("OK: Signature FOL pour ABA definie.") aba_parser_fol = AbaParser(fol_parser_for_aba) aba_parser_fol.setSymbolComma(";")print("INFO: Utilisation de ';' comme separateur pour le parser ABA FOL.")print(f"Chargement ABA (FOL) depuis fichier: {aba_fol_filepath}")try: aba_theory_fol = aba_parser_fol.parseBeliefBaseFromFile(str(aba_fol_filepath))print("OK: Theorie ABA (FOL) chargee depuis fichier.")exceptExceptionas e_ffol: print(f"Erreur chargement fichier ABA (FOL): {e_ffol}")if aba_theory_fol isnotNone:print("\nTheorie ABA (FOL):\n", str(aba_theory_fol)) reasoner_flat_stable_fol = FlatAbaReasoner(Semantics.STABLE_SEMANTICS) reasoner_pref_aba_fol = PreferredReasoner() FolFormula_class = jpype.JClass("org.tweetyproject.logics.fol.syntax.FolFormula") assumption_fol_query_str ="Pair(a,d)" assumption_fol = Assumption(JObject(fol_parser_for_aba.parseFormula(assumption_fol_query_str), FolFormula_class))print("\nRequetes sur la theorie ABA (FOL):")print(f" - Query '{assumption_fol}' (ABA Preferred)? {reasoner_pref_aba_fol.query(aba_theory_fol, assumption_fol)}")except jpype.JException as e_sig_java: print(f"Erreur Java lors de la config FOL pour ABA: {e_sig_java.message()}")exceptExceptionas e_sig_py: print(f"Erreur Python lors de la config FOL pour ABA: {e_sig_py}")exceptImportErroras e: print(f"Erreur d'import pour ABA : {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()
--- 4.4 Assumption-Based Argumentation (ABA) ---
JVM prete. Execution de l'exemple ABA...
OK: Imports ABA et dependances reussis.
--- Exemple ABA avec Logique Propositionnelle ---
Chargement ABA (PL) depuis fichier: resources\example2.aba
OK: Theorie ABA (PL) chargee depuis fichier.
Theorie ABA (PL): ABATheory [rules=[(q <- true), (p <- q, a), (r <- b, c)], assumptions=[a, b, c], negations=[]]
Requetes sur la theorie ABA (PL):
- Query 'a' (Flat Preferred)? True
- Query 'a' (ABA Preferred)? True
--- Exemple ABA avec Logique du Premier Ordre ---
OK: Signature FOL pour ABA definie.
INFO: Utilisation de ';' comme separateur pour le parser ABA FOL.
Chargement ABA (FOL) depuis fichier: resources\smp_fol.aba
OK: Theorie ABA (FOL) chargee depuis fichier.
Theorie ABA (FOL):
ABATheory [rules=[(WPrefers(c,a,b) <- true), (MPrefers(a,d,c) <- true), (ContraryPair(A,B) <- MPrefers(A,D,B), Pair(A,D)), (MPrefers(b,c,d) <- true), (ContraryPair(A,B) <- WPrefers(B,E,A), Pair(E,B)), (WPrefers(d,b,a) <- true)], assumptions=[Pair(a,d), Pair(b,c), Pair(a,c), Pair(b,d)], negations=[not Pair(A,B) = ContraryPair(A,B)]]
Requetes sur la theorie ABA (FOL):
- Query 'Pair(a,d)' (ABA Preferred)? False
Interpretation des résultats ABA
Exemple 1 : Logique Propositionnelle
La théorie example2.aba contient : - Règles : q <- true, p <- q, a, r <- b, c - Hypotheses (assumptions) : a, b, c - Contraires : (non définis dans cet exemple)
Requête a (Flat Preferred) : True
L’hypothese a est acceptee car : 1. Aucun argument ne l’attaque (pas de contraire défini) 2. Elle fait partie de toutes les extensions preferees
Exemple 2 : Logique du Premier Ordre (Stable Matching)
Le fichier smp_fol.aba modelise un problème de mariage stable : - Variables : Male = {a, b}, Female = {c, d} - Hypotheses : Pair(a,d), Pair(b,c), Pair(a,c), Pair(b,d) - Contraires : not Pair(A,B) = ContraryPair(A,B) - Préférences : MPrefers(a,d,c) = “a prefere d a c”
Requête Pair(a,d) (ABA Preferred) : False
Le couple (a, d) n’est PAS dans l’extension preferee car : 1. L’hypothese Pair(a,d) a un contraire ContraryPair(a,d) 2. Ce contraire est derivable via les préférences 3. Un autre appariement est prefere globalement
Point cle ABA : Les hypotheses sont “attaquables” via leurs contraires. C’est la principale différence avec ASPIC+ ou les attaques ciblent des règles ou conclusions.
4.5 Argumentation Déductive (PL)
Transition depuis ABA :
Origine. L’argumentation déductive quantitative (arguments pondérés, agrégation logique des poids) est développée par Besnard, P. & Hunter, A. (2008), Éléments of Argumentation, MIT Press — qui formalisent les arguments comme des ensembles de formules liés par conséquence logique, associent des poids (force) aux arguments, et définissent des fonctions d’agrégation pour scorer les conclusions pour/contre. C’est le pendant quantitatif des frameworks qualitatifs de Dung.
Après avoir exploré ABA (hypothèses + contraires), nous passons à une approche quantitative plutôt que qualitative : l’argumentation déductive de Besnard & Hunter.
Changement de paradigme : du qualitatif au quantitatif
Aspect
ASPIC+/DeLP/ABA
Argumentation Déductive
Approche
Qualitative (extension, warrant)
Quantitative (score numérique)
Output
Ensembles d’arguments acceptés
Score de force pour chaque conclusion
Comparaison
Ordre sur règles ou spécificité
Agrégation numérique (comptage)
Evaluation
In/Out d’une extension
Valeur réelle (positive/négative)
Qu’est-ce que l’argumentation déductive ?
Cette approche, souvent associée à Besnard & Hunter, construit des arguments comme des paires (Support, Conclusion) où : - Support : sous-ensemble minimal et consistant de la base de connaissances - Conclusion : formule logiquement impliquée par le support
Caractéristiques clés :
DeductiveKnowledgeBase: Une simple PlBeliefSet dans l’implémentation de Tweety
Argument: Généré implicitement par le raisonneur (pas besoin de les définir explicitement)
Attaque: Un argument (S1, C1) attaque (S2, C2) si :
C1 = ¬e où e ∈ S2 (attaque undercut : attaque une prémisse)
C1 = ¬C2 (attaque rebut : attaque la conclusion)
Mécanisme de raisonnement :
Le SimpleDeductiveReasoner construit un arbre d’arguments/contre-arguments pour une requête donnée :
Categorizer : Détermine la force initiale d’un argument
Ex: ClassicalCategorizer donne +1 à tout argument valide
Accumulator : Agrège la force des arguments/contre-arguments dans l’arbre
Ex: SimpleAccumulator fait la somme algébrique : force(pour) - force(contre)
Pourquoi une approche quantitative ?
Cette approche est utile pour des domaines où on veut mesurer la force des arguments plutôt que simplement accepter/rejeter : - Détection de fraude : Score de suspicion - Médecine légale : Degré de culpabilité - Analyse de risque : Niveau de menace
Exemple : Un suspect accusé par 1 témoin vs. 2 témoins innocentant → score -1 (plutôt innocent)
# --- 4.5 Argumentation Déductive (PL) ---print("\n--- 4.5 Argumentation Deductive (PL) ---")try:from org.tweetyproject.logics.pl.parser import PlParserfrom org.tweetyproject.arg.deductive.syntax import DeductiveKnowledgeBasefrom org.tweetyproject.arg.deductive.reasoner import SimpleDeductiveReasoner, AbstractDeductiveArgumentationReasonerfrom org.tweetyproject.arg.deductive.categorizer import ClassicalCategorizerfrom org.tweetyproject.arg.deductive.accumulator import SimpleAccumulatorfrom org.tweetyproject.logics.pl.sat import Sat4jSolver, SatSolver# --- Initialisation --- SatSolver.setDefaultSolver(Sat4jSolver()) parser_ded = PlParser() kb_ded = DeductiveKnowledgeBase()# Base de connaissances de l'exemple (Besnard & Hunter style)# s = suspect, h = coupable, f = fiable, v = victime formulas_ded = ["s", "!s || h", "f", "!f || !h", "v", "!v || !h"]for f_str in formulas_ded: kb_ded.add(parser_ded.parseFormula(f_str))print("KB Deductive:")for f in kb_ded:print(f" - {f}")print(f"\nInterpretation: s=suspect, h=coupable, f=fiable, v=victime")print(" - s et (s->h) impliquent h")print(" - f et (f->!h) impliquent !h")print(" - v et (v->!h) impliquent !h")# --- Raisonnement --- ded_reasoner = SimpleDeductiveReasoner(ClassicalCategorizer(), SimpleAccumulator()) query_ded = parser_ded.parseFormula("h") result_ded = ded_reasoner.query(kb_ded, query_ded)print(f"\nQuery 'h' (coupable)? {result_ded}")print(" (Plusieurs arguments s'opposent: s->h vs f->!h et v->!h)")exceptImportErroras e:print(f"Erreur d'import pour Argumentation Deductive : {e}")print(" Verifiez le JAR 'org.tweetyproject.arg.deductive'.")exceptExceptionas e:print(f"Erreur lors de l'execution de l'exemple Deductif: {e}")import traceback traceback.print_exc()
--- 4.5 Argumentation Deductive (PL) ---
KB Deductive:
- !f||!h
- !v||!h
- !s||h
- s
- f
- v
Interpretation: s=suspect, h=coupable, f=fiable, v=victime
- s et (s->h) impliquent h
- f et (f->!h) impliquent !h
- v et (v->!h) impliquent !h
Query 'h' (coupable)? -2.0
(Plusieurs arguments s'opposent: s->h vs f->!h et v->!h)
Interpretation du résultat Deductif
Score de la requête h (coupable) : -2.0
Le score negatif indique que la requête est refutee par le système : le poids agrege des arguments contreh l’emporte sur celui des arguments pour.
Arguments en presence :
Conclusion
Support
Rôle
h
{s, !s \|\| h}
un argument pour
!h
{f, !f \|\| !h}
un argument contre
!h
{v, !v \|\| !h}
un deuxieme argument contre
Comment le score est calcule (ClassicalCategorizer + SimpleAccumulator) : - Le ClassicalCategorizer (Besnard & Hunter) attribue a chaque argument une valeur derivee de son arbre dialectique (les defeaters sont consideres recursivement) — ce n’est donc pas un simple comptage a +1 / -1 par argument. - Le SimpleAccumulator retourne ensuite la différence entre la somme des valeurs des arguments pour et celle des arguments contre. - Ici l’agregat calcule par Tweety vaut -2.0 (cf. la sortie Query 'h' (coupable)? -2.0 de la cellule ci-dessus). C’est le signe — et non la valeur exacte, qui depend de la recursion du categoriseur — qui porte la conclusion : contre > pour, donc h est refutee.
Interpretation : Le suspect est accuse (s implique h), mais deux sources independantes (le temoin fiable f et la victime v) appuient l’innocence. Le bilan agrege penche du cote de !h.
Différence avec ASPIC+/DeLP : - Ici, pas de notion de specificite ou de préférence entre arguments - Le SimpleAccumulator agrege quantitativement les valeurs de categorisation pour / contre - ASPIC+/DeLP raisonnent plutot qualitativement (relations de defaite, préférences entre arguments)
4.6 Answer Set Programming (ASP)
Rupture paradigmatique : de l’argumentation vers la programmation logique
Le Answer Set Programming représente une rupture par rapport aux frameworks argumentatifs précédents :
Aspect
Frameworks argumentatifs
ASP
But principal
Justifier/réfuter des conclusions
Résoudre des problèmes combinatoires
Output
Extensions, scores, warrants
Answer Sets (modèles stables)
Approche
Arguments avec attaques
Programmation logique déclarative
Focus
Raisonnement défaisable
Recherche de solutions satisfiables
Qu’est-ce qu’ASP ?
ASP est un paradigme de programmation déclarative puissant pour résoudre des problèmes combinatoires complexes, souvent utilisé en représentation de connaissances et raisonnement. Un programme ASP est un ensemble de règles logiques (similaires à Prolog mais avec une sémantique différente basée sur les “modèles stables” ou “answer sets”).
Syntaxe ASP :
Règles de la forme tete :- corps. où corps est une conjonction de littéraux :
Deux types de négation : - Négation par défaut (not) : Closed World Assumption (si non prouvé, alors faux) - Négation classique (-) : Négation forte (explicite)
Permet aussi les contraintes (règles sans tête), les règles de choix ({a; b}) et les agrégats (#count, #sum, etc.)
Sémantique des Answer Sets :
Les “answer sets” sont des ensembles minimaux d’atomes vrais qui satisfont toutes les règles du programme. Un programme peut avoir : - 0 answer sets : Programme inconsistant - 1 answer set : Solution unique (déterministe) - Plusieurs answer sets : Plusieurs solutions possibles (choix non-déterministes)
Implémentation dans Tweety :
Program : Représente un programme ASP (org.tweetyproject.lp.asp.syntax)
Solveur externe requis : Clingo (de la suite Potassco)
ClingoSolver : Interface Tweety vers Clingo
Grounding : Clingo 5.0+ intègre le grounding en interne (instanciation des variables)
Pré-requis technique :
Nécessite l’installation de Clingo (Potassco) et la configuration du chemin vers l’exécutable dans EXTERNAL_TOOLS['CLINGO'] (voir cellule d’initialisation).
Cas d’usage typiques d’ASP :
Domaine
Application
Configuration
Sélection de composants compatibles
Planification
PDDL-like action planning
Diagnostic
Identification de pannes multiples
Puzzle solving
Sudoku, graphes, contraintes
Bioinformatique
Analyse de réseaux métaboliques
Pourquoi ASP dans un cours d’argumentation ?
ASP partage avec l’argumentation structurée : - La négation par défaut (raisonnement non-monotone) - Les modèles stables (sémantique de Gelfond-Lifschitz ≈ extensions de Dung) - L’approche déclarative (dire “quoi” pas “comment”)
Mais ASP est plus orienté résolution de problèmes que justification d’arguments.
# --- 4.6 Answer Set Programming (ASP) ---print("\n--- 4.6 Answer Set Programming (ASP) ---")ifnot jvm_ready:print("ERREUR: JVM non demarree.")else:print("JVM prete. Execution de l'exemple ASP...") asp_imports_ok =Falsetry:import jpypefrom jpype.types import*from java.util import ArrayList, List as JavaList, Collectionfrom org.tweetyproject.lp.asp.syntax import ( Program, ASPRule, ASPAtom, DefaultNegation, StrictNegation, ClassicalHead, AggregateHead, AggregateAtom, ASPHead, ASPBodyElement )from org.tweetyproject.logics.commons.syntax import Constant, Predicate, Variablefrom org.tweetyproject.lp.asp.reasoner import ClingoSolverfrom org.tweetyproject.lp.asp.grounder import GringoGrounderfrom org.tweetyproject.lp.asp.semantics import AnswerSetif'get_tool_path'notinglobals() or'EXTERNAL_TOOLS'notinglobals():raiseNameError("La fonction 'get_tool_path' ou 'EXTERNAL_TOOLS' n'est pas definie.") CLINGO_PATH = get_tool_path('CLINGO')print("OK: Imports ASP reussis.") asp_imports_ok =True# --- Programme ASP Simple ---print("\n--- Programme ASP Simple ---") p = ASPAtom("p"); r_atom = ASPAtom("r"); q = ASPAtom("q"); b_atom = ASPAtom("b") body1 = ArrayList(); body1.add(DefaultNegation(r_atom)) r1_asp = ASPRule(ClassicalHead(p), JObject(body1, JavaList)) body2 = ArrayList(); body2.add(StrictNegation(q)); body2.add(DefaultNegation(b_atom)) r2_asp = ASPRule(ClassicalHead(r_atom), JObject(body2, JavaList)) body3 = ArrayList(); body3.add(b_atom) r3_asp = ASPRule(ClassicalHead(StrictNegation(q)), JObject(body3, JavaList)) body4 = ArrayList() r4_asp = ASPRule(ClassicalHead(b_atom), JObject(body4, JavaList)) rules_prog1 = ArrayList([r1_asp, r2_asp, r3_asp, r4_asp]) program1 = Program(JObject(rules_prog1, Collection))print("Programme 1:\n", str(program1))# --- Programme ASP Suspects ---print("\n--- Programme ASP Suspects ---") motive = Predicate("motive", 1); guilty = Predicate("guilty", 1); innocent = Predicate("innocent", 1) harry = Constant("harry"); sally = Constant("sally") Suspect = Variable("Suspect") motive_h = ASPAtom(motive, [harry]); motive_s = ASPAtom(motive, [sally]) guilty_h = ASPAtom(guilty, [harry]) innocent_S = ASPAtom(innocent, [Suspect]); motive_S = ASPAtom(motive, [Suspect]) guilty_S = ASPAtom(guilty, [Suspect]) r1_sus = ASPRule(ClassicalHead(motive_h), JObject(ArrayList(), JavaList)) r2_sus = ASPRule(ClassicalHead(motive_s), JObject(ArrayList(), JavaList)) r3_sus = ASPRule(ClassicalHead(guilty_h), JObject(ArrayList(), JavaList)) body4_sus = ArrayList(); body4_sus.add(motive_S); body4_sus.add(DefaultNegation(guilty_S)) r4_sus = ASPRule(ClassicalHead(innocent_S), JObject(body4_sus, JavaList)) rules_prog2 = ArrayList([r1_sus, r2_sus, r3_sus, r4_sus]) program2 = Program(JObject(rules_prog2, Collection))print("Programme 2:\n", str(program2))# --- Raisonnement avec Clingo ---ifnot CLINGO_PATH:print("\nWARNING: Clingo non configure ou chemin invalide dans EXTERNAL_TOOLS['CLINGO'].")print(" Veuillez installer Clingo (via pip/conda ou manuellement) et configurer le chemin.")print(" Raisonnement ASP saute.")else:print(f"\nUtilisation de Clingo trouve/configure a: {CLINGO_PATH}")try: solver_instance = ClingoSolver(JString(CLINGO_PATH))print(f"\nCalcul des Answer Sets pour Programme 2...") answer_sets_collection = solver_instance.getModels(program2)print(f"Answer Sets trouves ({answer_sets_collection.size()}):")if answer_sets_collection.isEmpty():print(" (Aucun Answer Set)")else: count =1for ans_set in answer_sets_collection:try: atoms_in_set =", ".join(sorted([str(atom) for atom in ans_set]))print(f" - AS {count}: {{{atoms_in_set}}}")exceptException:print(f" - AS {count}: {ans_set}") count +=1# Grounding desactive car GringoGrounder incompatible avec Clingo 5.0+print("\nINFO: Grounding desactive (GringoGrounder incompatible avec Clingo 5.0+)")print(" Note: Clingo 5.0+ integre le grounding en interne.")except jpype.JException as e_clingo_java:print(f"Erreur Java lors de l'appel a Clingo: {e_clingo_java.message()}")print(" Verifiez que le chemin vers Clingo est correct et que Clingo fonctionne.")exceptExceptionas e_clingo_py:print(f"Erreur Python lors de l'appel a Clingo: {e_clingo_py}")import traceback; traceback.print_exc()exceptImportErroras e: print(f"Erreur d'import pour ASP : {e}. Verifiez le JAR 'lp.asp'.")except jpype.JException as e_java: print(f"Erreur Java generale ASP: {e_java.message()}")exceptExceptionas e_gen: print(f"Erreur Python inattendue ASP: {e_gen}");import traceback; traceback.print_exc()
--- 4.6 Answer Set Programming (ASP) ---
JVM prete. Execution de l'exemple ASP...
OK: Imports ASP reussis.
--- Programme ASP Simple ---
Programme 1:
{b. -q :- b. p :- not r. r :- -q, not b.}
--- Programme ASP Suspects ---
Programme 2:
{guilty(harry). innocent(Suspect) :- motive(Suspect), not guilty(Suspect). motive(harry). motive(sally).}
Utilisation de Clingo trouve/configure a: <repo>MyIA.AI.Notebooks\SymbolicAI\Tweety\ext_tools\clingo
Calcul des Answer Sets pour Programme 2...
Answer Sets trouves (1):
- AS 1: {guilty(harry), innocent(sally), motive(harry), motive(sally)}
INFO: Grounding desactive (GringoGrounder incompatible avec Clingo 5.0+)
Note: Clingo 5.0+ integre le grounding en interne.
Interpretation de l’Answer Set
Clingo a trouve un seul Answer Set pour le programme “Suspects” :
guilty(harry) : Harry est coupable (fait explicite)
Application de la règle defaisable :
innocent(Suspect) :- motive(Suspect), not guilty(Suspect)
Pour Harry : motive(harry) OK, mais not guilty(harry) FAUX -> pas innocent
Pour Sally : motive(sally) OK et not guilty(sally) VRAI -> innocent(sally)
Sémantique des modèles stables : - “not” est la negation par defaut (Closed World Assumption) - not guilty(sally) est vrai car guilty(sally) n’est pas derivable - L’Answer Set est minimal : il ne contient que les atomes necessaires
Unicite du modèle : - Un seul Answer Set car pas de choix non-déterministe dans le programme - Avec des règles de choix ({a ; b}), on aurait plusieurs Answer Sets
Exercice : Diagnostic de système avec Answer Set Programming (ASP)
La section 4.6 a montre les Answer Sets (modèles stables) avec negation par defaut. Mettez en pratique pour modeliser un diagnostic de pannes.
Contexte
Un système a 3 composants : alimentation, carte_mere, disque. Un composant est suspect s’il a un symptome et qu’on ne peut PAS prouver qu’il est teste_ok (negation par defaut not).
Objectifs
Construire un Program ASP avec faits et règle defaisable
Calculer les answer sets avec ClingoSolver
Interpreter : quels composants sont suspects ?
Indices :
Reprenez le pattern section 4.6 : Predicate, Constant, ASPAtom
DefaultNegation(atom) pour not atom
Attendu : un seul answer set avec suspect(alimentation) mais PAS suspect(disque)
# --- Exercice : Diagnostic de pannes avec ASP ---# TODO etudiant : modelisez un diagnostic de pannes avec Answer Set Programming## Etape 1 : importer les classes ASP (cf section 4.6)# from org.tweetyproject.lp.asp.syntax import Program, ASPRule, ASPAtom, ClassicalHead, DefaultNegation# from org.tweetyproject.logics.commons.syntax import Constant, Predicate# from org.tweetyproject.lp.asp.reasoner import ClingoSolver# from java.util import ArrayList## Etape 2 : definir predicats (symptome/1, teste_ok/1, suspect/1) et constantes# Etape 3 : creer les faits (corps vide) et la regle defaisable suspect(X) :- symptome(X), not teste_ok(X)# Etape 4 : assembler le Program et calculer les answer sets avec ClingoSolver# Etape 5 (bonus) : ajouter teste_ok(alimentation) et observer que suspect(alimentation) disparaitifnot jvm_ready:print("ERREUR: JVM non demarree.")else: program =None# TODO etudiant : remplacer par le Program ASP construit answer_sets =None# TODO etudiant : remplacer par solver.getModels(program)print("Exercice a completer")
Exercice a completer
Resume et Comparaison des Frameworks
Ce notebook a couvert les 5 principaux frameworks d’argumentation structuree :
Exemple guide : Argumentation pour un Système de Recommandation
Appliquez l’un des frameworks d’argumentation structurée pour construire un système de recommandation simple.
Objectifs
Modeliser une base de connaissances pour des recommandations de films
Définir des règles defeasibles ou hypothèses
Generer des arguments pour/contre chaque film
Determiner les recommandations finales
Instructions
Questions de reflexion
Comment les préférences utilisateur influencent-elles les recommandations ?
Que se passe-t-il si deux arguments s’attaquent mutuellement ?
Comment integrer des notes quantitatives (sur 5 etoiles) dans ce système ?
Extensions (bonus)
Implementez le même système avec ABA (hypothèses = préférences)
Ajoutez une dimension temporelle (films recents vs classiques)
Comparez les résultats avec un système de recommandation base sur le filtrage collaboratif
Checklist de completion
# Exercice: Choisissez un framework (ASPIC+, DeLP, ou ABA)# Exemple avec DeLP (le plus intuitif pour les recommandations)from org.tweetyproject.arg.delp.syntax import*# Exercice: Definissez une base de connaissances de films# Exemple: regles pour recommander des films selon les genresfilms_kb ="""% Regles strictes (faits)film(inception) <- true.film(titanic) <- true.film(matrix) <- true.% Regles defeasibles (peuvent etre contredites)<- genre(inception, sci_fi).<- genre(titanic, romance).<- genre(matrix, sci_fi).% Preferences utilisateur (a adapter)<- prefere(scifi) | utilisateur_geek.<- prefere(romance) | utilisateur_sentimental.% Regles de recommandation<- recommander(F) <- film(F), genre(F, G), prefere(G)."""# Exercice: Instanciez le raisonneur DeLP# reasoner = DelpReasoner()# Exercice: Posez une query# result = reasoner.query("recommander(X)")# Exercice: Analysez les arguments pour/contre# Quels films sont recommandes ? Pourquoi ?# Exercice: Ajoutez des contre-arguments# Exemple: "inception est trop complexe pour certains"print("Exercice : DeLP pour recommandation de films a completer")
Exercice : DeLP pour recommandation de films a completer
Conclusion
Ce notebook a permis d’explorer les aspects essentiels de tweety 6 structured argumentation. Les points cles :
Les concepts fondamentaux ont ete presentes et illustres
Les Exemple guides proposent une mise en pratique progressive
Les résultats obtenus permettent de valider la comprehension
Pour aller plus loin : approfondir les aspects avances du sujet et explorer les liens avec d’autres domaines.
Exercice de synthese : Comparer deux frameworks sur un domaine medical
Modelisez un debat medical (ex: faut-il administrer un traitement risque ?) en utilisant deux frameworks d argumentation structures différents (ex: ASPIC+ et DeLP) et comparez leurs conclusions.
Contraintes
Au moins 4 arguments : 2 pro-traitement, 2 contre-traitement
Au moins 1 attaque entre arguments
Appliquer chaque framework et afficher les arguments acceptes
Comparer les résultats : les deux frameworks s accordent-ils ?
Étapes : 1. Définir les règles strictes et defaisables 2. Construire les arguments et leurs relations d attaque 3. Calculer l acceptabilite avec ASPIC+ puis avec DeLP 4. (Bonus) Identifier un cas ou les deux frameworks divergent
# TODO etudiant : comparer ASPIC+ et DeLP sur un domaine medical## Etape 1 : definir les arguments (pro et contre un traitement)# Etape 2 : definir les attaques entre arguments# Etape 3 : calculer l'acceptabilite avec chaque framework (ASPIC+ puis DeLP)# Etape 4 (bonus) : identifier une divergence entre les deux semantiquesprint("Exercice a completer") # TODO etudiant : remplacer par votre implementation