Argumentation Structuree

Navigation: <- Tweety-5-Abstract-Argumentation | Index | Tweety-7a-Extended-Frameworks ->


Introduction : De l’abstrait au structuré

Après avoir étudié l’argumentation abstraite (Dung) dans le notebook précédent, nous entrons maintenant dans l’argumentation structurée.

Différence fondamentale :

Aspect Argumentation abstraite (Dung) Argumentation structurée
Arguments Abstraits (nœuds sans contenu) Structurés (conclusion + support logique)
Attaques Relation binaire donnée manuellement Dérivée automatiquement du contenu
Base de données Pas de KB Base de connaissances + règles d’inférence
Génération Arguments fixés a priori Arguments construits automatiquement

Pourquoi passer au structuré ?

  1. Traçabilité : On voit pourquoi un argument attaque un autre (pas juste “A attaque B”)
  2. Génération automatique : Les arguments sont dérivés depuis une base de connaissances
  3. Logique sous-jacente : Utilise PL, FOL, ASP, etc. pour exprimer les connaissances
  4. Applications réelles : Permet de modéliser des domaines complexes (droit, médecine, IA explicable)

Objectifs pedagogiques

  1. Maitriser le framework ASPIC+ et sa conversion vers Dung
  2. Decouvrir DeLP (Defeasible Logic Programming) avec spécificité généralisée
  3. Explorer ABA (Assumption-Based Argumentation) avec hypothèses attaquables
  4. Comprendre l’argumentation deductive (Besnard & Hunter) avec scoring quantitatif
  5. Utiliser ASP (Answer Set Programming) avec Clingo pour résoudre des problèmes combinatoires

Les 5 frameworks de ce notebook :

Framework Approche Classes Tweety principales
ASPIC+ Règles strictes/défaisables, convertible en Dung AspicArgumentationTheory, DefeasibleInferenceRule
DeLP Programmation logique avec warrant dialectique DelpParser, DelpReasoner, GeneralizedSpecificity
ABA Hypothèses avec contraires AbaTheory, Assumption, FlatAbaReasoner
Déductif Support minimal avec scoring DeductiveKnowledgeBase, ClassicalCategorizer
ASP Modèles stables (Answer Sets) Program, ASPRule, ClingoSolver

Prerequis

Executez d’abord Tweety-01-Setup-Python.ipynb pour configurer l’environnement JVM.

Duree estimee : 35-45 minutes

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 = False

import jpype
import jpype.imports
import os
import pathlib
import shutil
import 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, "")
    if not path_str:
        return None
    if shutil.which(path_str):
        return path_str
    path_obj = pathlib.Path(path_str)
    if path_obj.is_file():
        return str(path_obj.resolve())
    if path_obj.is_dir():
        return str(path_obj.resolve())
    return None

# --- Auto-detection des outils ---
system = platform.system()
exe_suffix = ".exe" if system == "Windows" else ""

# 1. Clingo (ASP solver) - Tweety attend le REPERTOIRE
for 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 if isinstance(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()) if isinstance(sp, pathlib.Path) else sp
        break

# 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) if isinstance(ep, str) else ep
        if 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 = True
else:
    jdk_portable = None
    for 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}")
                break

    if not os.environ.get("JAVA_HOME"):
        print("ERREUR: JAVA_HOME non defini et JDK portable non trouve.")
    else:
        LIB_DIR = pathlib.Path("libs")
        if not 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 = True
                except Exception as 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] if len(path) > 30 else path
            print(f"  {tool}: {short_path}")
    print(f"\nJVM prete. Outils: {sum(1 for t,p in EXTERNAL_TOOLS.items() if p)}/{len(EXTERNAL_TOOLS)}")
--- Verification JVM Tweety + Outils ---
JDK portable: zulu17.50.19-ca-jdk17.0.11-win_x64
JVM demarree avec 42 JARs.

--- Outils disponibles ---
  CLINGO: clingo
  SPASS: SPASS.exe
  EPROVER: eprover.exe
  SAT_SOLVER_PYTHON: sat_solver.py
  MARCO: marco.py

JVM prete. Outils: 5/5

4.2 ASPIC+

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) ---")

if not jvm_ready:
    print("ERREUR: JVM non demarree.")
else:
    print("JVM prete. Execution de l'exemple ASPIC+...")
    try:
        import jpype
        from jpype.types import *
        from org.tweetyproject.logics.pl.syntax import Proposition, Negation, PlFormula
        from org.tweetyproject.arg.aspic.syntax import AspicArgumentationTheory, DefeasibleInferenceRule, StrictInferenceRule
        from org.tweetyproject.arg.aspic.ruleformulagenerator import PlFormulaGenerator
        from org.tweetyproject.arg.dung.syntax import Argument as DungArgument, Attack as DungAttack, DungTheory
        from org.tweetyproject.arg.dung.reasoner import SimpleGroundedReasoner

        print("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()}")
        except Exception as e_conv_py:
            print(f"Erreur Python lors de la conversion ASPIC->Dung: {e_conv_py}")

    except ImportError as 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()}")
    except Exception as 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 :

  • Axiomes : budget_disponible, equipe_prete
  • Règle defaisable r1 : budget_disponible, equipe_prete => approuver
  • Règle defaisable r2 : risque_eleve => rejeter
  • Règle defaisable r3 : approuver => !rejeter

Le conflit : si risque_eleve etait aussi un axiome, les arguments pour approuver et rejeter s’attaqueraient mutuellement.

Objectifs

  1. Construire une théorie AspicArgumentationTheory avec les 3 règles et 2 axiomes
  2. Convertir en AF de Dung avec asDungTheory()
  3. Calculer l’extension grounded avec SimpleGroundedReasoner
  4. 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 conflit

if not 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 grounded
    print("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) ---")

if not jvm_ready:
    print("ERREUR: JVM non demarree.")
else:
    print("JVM prete. Execution de l'exemple DeLP...")
    try:
        # Imports
        import jpype
        from jpype.types import *
        import pathlib
        from java.io import StringReader
        from java.util import ArrayList

        # Imports DeLP
        from org.tweetyproject.arg.delp.parser import DelpParser
        from org.tweetyproject.arg.delp.reasoner import DelpReasoner
        from org.tweetyproject.arg.delp.semantics import GeneralizedSpecificity
        from org.tweetyproject.arg.delp.syntax import DefeasibleLogicProgram

        # Imports FOL/Commons necessaires
        from org.tweetyproject.logics.fol.syntax import FolFormula, FolSignature, FolAtom
        from org.tweetyproject.logics.commons.syntax import Constant, Predicate

        print("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()

        if not 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.")
            except Exception as e_str: print(f"Erreur parsing chaine integree: {e_str}"); delp_program = None
        else:
            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.")
            except Exception as e_file: print(f"Erreur chargement fichier: {e_file}"); delp_program = None


        # --- Raisonnement DeLP ---
        if delp_program is not None:
            print("\nProgramme DeLP charge:\n", str(delp_program))

            # DEBUG Signature
            sig_delp = None
            try:
                sig_delp = delp_program.getSignature()
                print("\nSignature extraite par DelpParser:")
                print(sig_delp)
                if hasattr(sig_delp, 'getPredicates'): print("Predicates:", sig_delp.getPredicates())
                if hasattr(sig_delp, 'getConstants'): print("Constants:", sig_delp.getConstants())
            except Exception as 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, opus
            print("\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.")

            except Exception as e_build:
                print(f"Erreur lors de la construction programmatique des requetes: {e_build}")
                queries_fol_obj = None

            if 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()}")
                    except Exception as 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 NO
                print("\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.")

    except ImportError as 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()}")
    except Exception as 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

Exemple typique :

Hypothèses : {diabète, grippe, allergie}
Contraires : non_diabète, non_grippe, non_allergie
Règles : fièvre <- grippe
         toux <- allergie
         fatigue <- diabète

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) ---")

if not 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 StringReader
        from org.tweetyproject.arg.aba.parser import AbaParser
        from org.tweetyproject.arg.aba.syntax import AbaTheory, Assumption
        from org.tweetyproject.logics.pl.parser import PlParser
        from org.tweetyproject.logics.pl.syntax import Proposition, PlFormula
        from org.tweetyproject.logics.fol.parser import FolParser
        from org.tweetyproject.logics.fol.syntax import FolFormula, FolSignature
        from org.tweetyproject.logics.pl.sat import SatSolver, Sat4jSolver
        from org.tweetyproject.arg.aba.reasoner import FlatAbaReasoner, PreferredReasoner
        from org.tweetyproject.arg.dung.semantics import Semantics
        from org.tweetyproject.arg.dung.syntax import DungTheory

        print("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 = None
        if not 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.")
            except Exception as e_fpl: print(f"Erreur chargement fichier ABA (PL): {e_fpl}")

        if aba_theory_pl is not None:
            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 = None

        if not 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.")
                 except Exception as e_ffol: print(f"Erreur chargement fichier ABA (FOL): {e_ffol}")

                 if aba_theory_fol is not None:
                       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()}")
            except Exception as e_sig_py: print(f"Erreur Python lors de la config FOL pour ABA: {e_sig_py}")

    except ImportError as e: print(f"Erreur d'import pour ABA : {e}.")
    except jpype.JException as e_java: print(f"Erreur Java generale: {e_java.message()}")
    except Exception as 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 :

  1. Categorizer : Détermine la force initiale d’un argument
    • Ex: ClassicalCategorizer donne +1 à tout argument valide
  2. 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 PlParser
    from org.tweetyproject.arg.deductive.syntax import DeductiveKnowledgeBase
    from org.tweetyproject.arg.deductive.reasoner import SimpleDeductiveReasoner, AbstractDeductiveArgumentationReasoner
    from org.tweetyproject.arg.deductive.categorizer import ClassicalCategorizer
    from org.tweetyproject.arg.deductive.accumulator import SimpleAccumulator
    from 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)")

except ImportError as e:
     print(f"Erreur d'import pour Argumentation Deductive : {e}")
     print("   Verifiez le JAR 'org.tweetyproject.arg.deductive'.")
except Exception as 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 contre h 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 :

coupable(X) :- suspect(X), motif(X), not innocent(X).   % Règle défaisable
innocent(X) :- temoin_fiable(Y), dit_innocent(Y, X).    % Règle normale
:- coupable(X), innocent(X).                             % Contrainte (interdit incohérence)

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) ---")

if not jvm_ready:
    print("ERREUR: JVM non demarree.")
else:
    print("JVM prete. Execution de l'exemple ASP...")
    asp_imports_ok = False
    try:
        import jpype
        from jpype.types import *
        from java.util import ArrayList, List as JavaList, Collection
        from 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, Variable
        from org.tweetyproject.lp.asp.reasoner import ClingoSolver
        from org.tweetyproject.lp.asp.grounder import GringoGrounder
        from org.tweetyproject.lp.asp.semantics import AnswerSet

        if 'get_tool_path' not in globals() or 'EXTERNAL_TOOLS' not in globals():
            raise NameError("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 ---
        if not 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 = 1
                    for 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}}}")
                        except Exception:
                            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.")
            except Exception as e_clingo_py:
                print(f"Erreur Python lors de l'appel a Clingo: {e_clingo_py}")
                import traceback; traceback.print_exc()

    except ImportError as 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()}")
    except Exception as 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), innocent(sally), motive(harry), motive(sally)}

Derivation pas a pas :

  1. Faits de base (toujours vrais) :
    • motive(harry) : Harry a un motif
    • motive(sally) : Sally a un motif
    • guilty(harry) : Harry est coupable (fait explicite)
  2. 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

  1. Construire un Program ASP avec faits et règle defaisable
  2. Calculer les answer sets avec ClingoSolver
  3. 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) disparait

if not 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 :

Framework Caractéristiques Classes Tweety principales
ASPIC+ Règles strictes/defaisables, conversion vers Dung AspicArgumentationTheory, DefeasibleInferenceRule
DeLP Programmation logique defaisable, warrant dialectique DelpParser, DelpReasoner, GeneralizedSpecificity
ABA Arguments via hypotheses attaquables, contraires AbaTheory, Assumption, FlatAbaReasoner
Deductif Support minimal, scoring quantitatif DeductiveKnowledgeBase, ClassicalCategorizer, SimpleAccumulator
ASP Answer Sets (modèles stables), Clingo Program, ASPRule, ClingoSolver

Comparaison detaillee des approches :

Critere ASPIC+ DeLP ABA Deductif ASP
Structure arguments Règles Règles Hypotheses Support minimal Règles logiques
Negation Classique Defaut + Classique Contraires Classique Defaut + Classique
Comparaison Ordre sur règles Specificite Contraires Agregation numérique Minimalite
Output Extensions YES/NO/UNDECIDED Extensions Score reel Answer Sets
Solveur externe Non Non Non Non Clingo requis
Conversion Dung Oui Non Oui Non Non direct
Domaines typiques IA explicable Droit, medecine Diagnostic Detection fraude Puzzles, config

Quand utiliser chaque framework ?

Besoin Framework recommande Raison
Exploiter sémantiques de Dung ASPIC+ Conversion directe en AF abstrait
Exceptions hierarchisees DeLP Specificite generalisee intuitive
Tester hypotheses ABA Hypotheses attaquables via contraires
Mesurer force arguments Deductif Scoring quantitatif
Problemes combinatoires ASP Puissance de Clingo, optimisation

Points communs a tous les frameworks :

  1. Raisonnement non-monotone : Ajouter des faits peut invalider des conclusions
  2. Arguments structures : Pas de boite noire, traçabilite complete
  3. Base de connaissances : Arguments construits automatiquement depuis KB
  4. Logique sous-jacente : PL ou FOL (sauf ASP qui a sa propre syntaxe)

Evolution historique :

1995: Dung (abstrait)
  ↓
2000s: ASPIC, DeLP, ABA (structuré, logique)
  ↓
2010s: Extensions (pondéré, probabiliste, graduel)
  ↓
2020s: Hybrides (neural-symbolic, LLMs + argumentation)

Différences philosophiques :

  • ASPIC+ : Approche syntaxique (règles explicites)
  • DeLP : Approche dialectique (argumentation pour/contre)
  • ABA : Approche hypothetico-deductive (test d’hypotheses)
  • Deductif : Approche quantitative (mesure de force)
  • ASP : Approche resolution de problemes (satisfaction de contraintes)

Apprentissages cles

  1. Passage abstrait → structure = gain en traçabilite, perte en generalite
  2. Tweety unifie tous ces frameworks dans une API commune
  3. Conversions Dung : ASPIC+ et ABA peuvent beneficier des raisonneurs Dung
  4. ASP : Puissant mais paradigme différent (moins “argumentatif”, plus “logique”)
  5. Choix du framework depend du domaine et des besoins (qualitatif vs quantitatif)

Prochaines étapes

Le notebook suivant (Tweety-7a-Extended-Frameworks) explore les extensions avancees : - ADF (Abstract Dialectical Frameworks) : Generalisation de Dung avec liens d’acceptation - Frameworks ponderes : Arguments avec poids, attaques graduelles - Argumentation probabiliste : Incertitude sur arguments/attaques - Ranking semantics : Ordre total sur arguments (pas juste In/Out) - Argumentation sociale : Vote, agregation d’opinions


Navigation: <- Tweety-5-Abstract-Argumentation | Index | Tweety-7a-Extended-Frameworks ->

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

  1. Modeliser une base de connaissances pour des recommandations de films
  2. Définir des règles defeasibles ou hypothèses
  3. Generer des arguments pour/contre chaque film
  4. Determiner les recommandations finales

Instructions

Questions de reflexion

  1. Comment les préférences utilisateur influencent-elles les recommandations ?
  2. Que se passe-t-il si deux arguments s’attaquent mutuellement ?
  3. 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 genres
films_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 semantiques

print("Exercice a completer")  # TODO etudiant : remplacer par votre implementation
Exercice a completer
Retour au sommet