A la fin de ce notebook, vous saurez : 1. Lire et comprendre la syntaxe PDDL (Planning Domain Definition Language) 2. Ecrire un fichier domaine PDDL avec predicats et actions 3. Ecrire un fichier problème PDDL avec objets, etat initial et but 4. Utiliser unified-planning pour manipuler des modèles PDDL en Python 5. Comprendre les schemas d’action et leur instanciation
Prerequis
Python 3.9+
Connaissances basiques en logique propositionnelle
PDDL (Planning Domain Definition Language) est le langage standard pour decrire des problemes de planification automatique. Developpe en 1998 pour la première competition internationale de planification (IPC), il est base sur le modèle STRIPS avec des extensions.
Pourquoi PDDL ?
Avantage
Description
Standardisation
Format commun pour tous les planificateurs
Separation
Domaine (reutilisable) vs Problème (spécifique)
Expressivite
Typage, predicats, actions parametrees
Extensibilite
Nombreuses extensions (temporel, numérique, etc.)
Architecture PDDL
Un problème de planification en PDDL se compose de deux fichiers :
Domaine (domain.pddl) : Définit les types, predicats et actions disponibles
Problème (problem.pddl) : Définit les objets, l’etat initial et le but
1.1 STRIPS : La base de PDDL
PDDL est base sur le modèle STRIPS (Stanford Research Institute Problem Solver, 1971). Dans STRIPS, une action est définie par :
Composante
Description
Nom
Identifiant de l’action
Paramètres
Variables instanciees lors de l’exécution
Preconditions
Conditions necessaires pour executer l’action
Effets
Changements après l’exécution (ajouts et suppressions)
Changements : additions et suppressions de predicats
3. Exemple complet : Domaine Logistics
Le domaine Logistics est un classique de la planification. Un robot doit deplacer des colis entre des lieux en utilisant des vehicules (camions, avions).
Sortie obtenue : Le domaine PDDL est défini avec 3 actions et 4 predicats.
Élément
Type
Signification
Types
location, package, vehicle, truck
Hiérarchie d’objets
Predicats
at-loc, at-veh, in, empty
Etats du monde
Actions
load, unload, drive
Opérations possibles
Structure des actions : - load(p, v, l) : Charge le colis p dans le vehicule v au lieu l - Preconditions: colis present, vehicule present, vehicule vide - Effets: colis dans vehicule, plus au lieu, vehicule n’est plus vide
unload(p, v, l) : Decharge le colis p du vehicule v au lieu l
Preconditions: colis dans vehicule, vehicule au lieu
Effets: colis au lieu, plus dans vehicule, vehicule vide
drive(v, from, to) : Deplace le vehicule v de from vers to
Preconditions: vehicule au lieu de depart
Effets: vehicule au lieu d’arrivee, plus au lieu de depart
Note technique : Le domaine est reutilisable pour tous les problemes de logistique (nombre de colis, lieux, vehicules variable).
4. Structure d’un fichier problème PDDL
Le fichier problème définit une instance spécifique du domaine.
Le planificateur doit trouver une sequence d’actions qui rend tous les predicats du but vrais.
5. Exemple complet : Problème Logistics
# Definition du probleme PDDL - LogisticsLOGISTICS_PROBLEM ="""(define (problem logistics-simple-1) (:domain logistics-simple) (:objects ;; Lieux depot warehouse store - location ;; Colis a livrer box1 box2 - package ;; Vehicules truck1 - truck ) (:init ;; Positions initiales des colis (at-loc box1 depot) (at-loc box2 depot) ;; Position initiale du camion (at-veh truck1 depot) ;; Le camion est vide (empty truck1) ) (:goal (and ;; box1 doit etre au store (at-loc box1 store) ;; box2 doit etre au warehouse (at-loc box2 warehouse) )))"""print("Probleme PDDL defini : logistics-simple-1")print("\nEtat initial :")print(" - box1, box2 au depot")print(" - truck1 au depot (vide)")print("\nBut :")print(" - box1 au store")print(" - box2 au warehouse")
Probleme PDDL defini : logistics-simple-1
Etat initial :
- box1, box2 au depot
- truck1 au depot (vide)
But :
- box1 au store
- box2 au warehouse
Interpretation : Problème Logistics
Sortie obtenue : Le problème est instancie avec 6 objets (3 lieux, 2 colis, 1 camion).
Élément
Valeur
Signification
Objets
depot, warehouse, store, box1, box2, truck1
Instances concrètes
Etat initial
box1,box2@depot, truck1@depot(vide)
Tout au depot
But
box1@store, box2@warehouse
Livraison spécifique
Complexite du problème : - Espace d’etats : Chaque colis peut etre a 3 lieux ou dans 1 camion = 4^2 = 16 etats de colis - Position camion : 3 lieux possibles - Total : ~48 etats (sans compter l’etat vide/plein du camion) - Solution optimale : 7 actions (load, drive, unload, drive, load, drive, unload)
Contraintes : - Le camion ne peut porter qu’un colis a la fois (predicat empty) - Il faut revenir au depot pour charger le deuxieme colis
Note technique : C’est un problème de “transport” classique. La difficulte vient de la coordination entre les deplacements du vehicule et les chargements/dechargements des colis.
La bibliotheque unified-planning permet de manipuler des modèles PDDL directement en Python, sans ecrire de fichiers PDDL manuellement.
# Verification de unified-planningtry:import unified_planning as upfrom unified_planning.shortcuts import*print(f"unified-planning version: {up.__version__}") UP_AVAILABLE =TrueexceptImportError:print("ERREUR: unified-planning non installe")print("Installez avec: pip install unified-planning") UP_AVAILABLE =False
unified-planning version: 1.3.0
Interpretation : Verification unified-planning
Sortie obtenue : unified-planning version 1.3.0 est correctement installe.
Composant
Version
Signification
unified-planning
1.3.0
Version stable et recente
Points cles : 1. Cette version supporte tous les planificateurs modernes 2. L’API raccourcie (from unified_planning.shortcuts import *) simplifie la modelisation 3. Les types, fluents et actions peuvent etre définis programmatiquement
Note technique : unified-planning est le fruit d’un effort europeen (AI Plan4EU) pour standardiser l’interface de planification en Python.
Interpretation : Definition des types et predicats
Sortie obtenue : La hiérarchie de types et les predicats sont correctement définis.
Concept Python
Concept PDDL
Exemple
UserType('Location')
Type location
Lieu
UserType('Truck', father=Vehicle)
Sous-type
truck - vehicle
Fluent('at_loc', ...)
Predicat
(at-loc ?p - package ?l - location)
BoolType()
Valeur booleenne
Vrai/Faux
Points cles : 1. Les types definissent la structure des objets du monde 2. Les fluents (predicats) representent les etats changeants 3. L’heritage Truck -> Vehicle permet de reutiliser les actions vehicule pour les camions 4. OrderedDict assure l’ordre des paramètres (important pour unified-planning 1.3+)
Note technique : Contrairement a PDDL texte ou les paramètres sont nommes par convention (?p - package), unified-planning requiert des noms explicites dans le dictionnaire de signature.
Points cles : 1. Les paramètres sont recuperes via action.parameter('name') 2. add_effect(fluent, False) ajoute une negation (not fluent) 3. Les preconditions sont implicitement en ET (conjonction)
Note technique : La méthode parameter() retourne une Expression qui peut etre utilisee directement dans les fluents. C’est plus elegant que de manipuler des chaînes de caractères.
6.3 Creation du problème complet
if UP_AVAILABLE:# Creation du probleme problem = Problem('logistics-example')# Ajout des objets depot = Object('depot', Location) warehouse = Object('warehouse', Location) store = Object('store', Location) box1 = Object('box1', Package) box2 = Object('box2', Package) truck1 = Object('truck1', Truck) problem.add_objects([depot, warehouse, store, box1, box2, truck1])# Etat initial problem.set_initial_value(at_loc(box1, depot), True) problem.set_initial_value(at_loc(box2, depot), True) problem.set_initial_value(at_veh(truck1, depot), True) problem.set_initial_value(empty(truck1), True)# But problem.add_goal(at_loc(box1, store)) problem.add_goal(at_loc(box2, warehouse))# Ajout des actions au probleme problem.add_action(load) problem.add_action(unload) problem.add_action(drive)print("Probleme cree avec unified-planning")print(f"Objets: {[o.name for o in problem.all_objects]}")print(f"Actions: {[a.name for a in problem.actions]}")print(f"Buts: {[str(g) for g in problem.goals]}")
Probleme cree avec unified-planning
Objets: ['depot', 'warehouse', 'store', 'box1', 'box2', 'truck1']
Actions: ['load', 'unload', 'drive']
Buts: ['at_loc(box1, store)', 'at_loc(box2, warehouse)']
Interpretation : Problème complet
Sortie obtenue : Le problème est complet avec 6 objets, 3 actions et 2 buts.
Élément
Valeur
Signification
Objets
depot, warehouse, store, box1, box2, truck1
Instances du monde
Actions
load, unload, drive
Opérations disponibles
Buts
at_loc(box1, store), at_loc(box2, warehouse)
Objectifs
Étapes de creation : 1. Creation du problème : Problem('logistics-example') 2. Ajout des objets : Instanciation des types 3. Etat initial : Valeurs initiales des fluents (True/False) 4. Buts : Conditions a atteindre (conjonction de fluents) 5. Actions : Ajout des schemas d’action définis plus haut
Verification : - Tous les objets sont correctement types - L’etat initial est coherent (un colis ne peut etre qu’a un seul endroit) - Les buts sont realisables (pas de contradiction)
Note technique : Le problème peut maintenant etre passe a n’importe quel planificateur supporte par unified-planning (pyperplan, Fast Downward, ENHSP, etc.).
6.4 Resolution du problème
if UP_AVAILABLE:from unified_planning.engines import PlanGenerationResultStatusfrom unified_planning.shortcuts import get_environment get_environment().credits_stream =Nonetry:# Utiliser un planificateur disponiblewith OneshotPlanner(name='pyperplan') as planner:print(f"Planificateur: {planner.name}")print("Resolution en cours...\n") result = planner.solve(problem)if result.status == PlanGenerationResultStatus.SOLVED_SATISFICING:print("Solution trouvee !")print("="*50)for i, action inenumerate(result.plan.actions): params =', '.join(str(p.object()) for p in action.actual_parameters)print(f" {i+1}. {action.action.name}({params})")print("="*50)print(f"Longueur du plan: {len(result.plan.actions)} actions")else:print(f"Statut: {result.status}")exceptExceptionas e:print(f"Erreur: {e}")print("\nSolution attendue (manuelle):")print(" 1. load(box1, truck1, depot)")print(" 2. drive(truck1, depot, store)")print(" 3. unload(box1, truck1, store)")print(" 4. drive(truck1, store, depot)")print(" 5. load(box2, truck1, depot)")print(" 6. drive(truck1, depot, warehouse)")print(" 7. unload(box2, truck1, warehouse)")
Le planificateur trouve une sequence d’actions qui transforme l’etat initial en etat but :
Étape
Action
Etat après
0
(initial)
box1,box2@depot, truck1@depot
1
load(box1, truck1, depot)
box1 in truck1
2
drive(truck1, depot, store)
truck1@store
3
unload(box1, truck1, store)
box1@store (but 1 OK)
4
drive(truck1, store, depot)
truck1@depot
5
load(box2, truck1, depot)
box2 in truck1
6
drive(truck1, depot, warehouse)
truck1@warehouse
7
unload(box2, truck1, warehouse)
box2@warehouse (but 2 OK)
Note : Ce plan de 7 actions est optimal en longueur. Le camion de capacite 1 (predicat empty) ne transporte qu’un colis a la fois : chaque colis impose donc un aller-retour (load -> drive -> unload, puis drive de retour pour aller chercher le suivant), soit 7 actions au minimum – aucun plan plus court n’existe. pyperplan renvoie l’un des plans optimaux equivalents (l’ordre de traitement de box1/box2 peut varier d’une exécution a l’autre).
7. Extensions PDDL avances
PDDL dispose de nombreuses extensions au-delà de STRIPS de base.
Sortie obtenue : Le domaine Gripper est défini avec 3 actions et 7 predicats (3 de typage + 4 relationnels).
Élément
Description
Types
room (lieu), ball (balle), gripper (pince)
Predicats de typage
room, ball, gripper (declarations des sortes d’objets)
Predicats relationnels
at-robby (robot), at (balle), free (pince libre), carry (balle tenue)
Actions
move (deplacer), pick (prendre), drop (poser)
Specificites du domaine : - Le robot a deux pinces (left, right) independantes - Les balles peuvent etre transportees simultanement - Le robot peut se deplacer entre les pieces
Actions detaillees : - move(from, to) : Deplace le robot d’une piece a l’autre - pick(ball, room, gripper) : Prend une balle avec une pince (doit etre dans la même piece) - drop(ball, room, gripper) : Pose une balle dans une piece
Note technique : Ce domaine illustre l’importance de bien modeliser les ressources (les 2 pinces). Une mauvaise modelisation serait d’avoir un seul predicat free sans preciser quelle pince.
Definition du problème PDDL correspondant au domaine Gripper, instanciant les objets concrets, l’etat initial et le but a atteindre.
# Probleme PDDL du GripperGRIPPER_PROBLEM ="""(define (problem strips-gripper2) (:domain gripper-strips) (:objects rooma roomb - room ball1 ball2 - ball left right - gripper ) (:init ;; Definition des objets (optionnel dans certains planificateurs) (room rooma) (room roomb) (ball ball1) (ball ball2) (gripper left) (gripper right) ;; Position initiale du robot (at-robby rooma) ;; Pinces libres (free left) (free right) ;; Positions initiales des balles (at ball1 rooma) (at ball2 rooma) ) (:goal (and (at ball1 roomb) (at ball2 roomb) )))"""print("Probleme Gripper defini")print("\nEtat initial:")print(" - Robot dans rooma")print(" - ball1, ball2 dans rooma")print(" - Pinces left, right libres")print("\nBut:")print(" - ball1 et ball2 dans roomb")
Probleme Gripper defini
Etat initial:
- Robot dans rooma
- ball1, ball2 dans rooma
- Pinces left, right libres
But:
- ball1 et ball2 dans roomb
Interpretation : Problème Gripper
Sortie obtenue : Le problème est instancie avec 6 objets et 11 predicats initiaux.
Élément
Valeur
Signification
Objets
2 rooms, 2 balls, 2 grippers
Instances du monde
Etat initial
Robot + balles dans rooma, pinces libres
Tout au depart
But
Les 2 balles dans roomb
Transport complet
Analyse de l’etat initial : - at-robby rooma : Robot dans la piece rooma - at ball1 rooma, at ball2 rooma : Balles dans rooma - free left, free right : Les deux pinces sont libres
Stratégie optimale : 1. Prendre ball1 avec la pince gauche 2. Prendre ball2 avec la pince droite 3. Se deplacer vers roomb 4. Poser ball1 5. Poser ball2
Observation : Le robot peut porter les 2 balles en même temps ! Un planificateur qui n’utilise pas cette capacite ferait 7 actions au lieu de 5 (prendre, deplacer, poser, revenir, reprendre, deplacer, poser).
Analyse du problème Gripper
Élément
Valeur
Objets
2 rooms, 2 balls, 2 grippers
Etat initial
Robot + balles dans rooma
But
Balles dans roomb
Actions possibles
move, pick (x2), drop (x2)
Une solution optimale : 1. pick(ball1, rooma, left) 2. pick(ball2, rooma, right) 3. move(rooma, roomb) 4. drop(ball1, roomb, left) 5. drop(ball2, roomb, right)
Observation : Le robot peut porter deux balles simultanement car il a deux pinces !
9. Exercices
Exercice 9.1 - Etendre le problème Gripper
Le problème Gripper de la section 8 transporte 2 balles entre 2 pieces. A vous de jouer : ecrivez le problème PDDL (le domaine gripper-strips reste inchange) pour la variante suivante :
3 pieces : rooma, roomb, roomc
3 balles : ball1, ball2, ball3, toutes initialement dans rooma
Robot : demarre dans rooma, ses deux pinces left et right sont libres
But : ball1 et ball2 dans roomc, ball3 dans roomb
Completez le squelette de la cellule suivante en reutilisant la structure de GRIPPER_PROBLEM (sections :objects, :init, :goal).
Indice : le robot ne possede que 2 pinces mais doit livrer dans 2 pieces différentes. Une partie du transport necessitera donc un aller-retour. Reportez-vous a l’encadre methodologique ci-dessous pour la demarche.
# Exercice 9.1 : Probleme Gripper a 3 pieces / 3 balles# Le domaine gripper-strips (defini plus haut) reste INCHANGE : seul le# probleme change. Completez la chaine PDDL ci-dessous en vous inspirant# de GRIPPER_PROBLEM (section 8) et de l'enonce.GRIPPER_PROBLEM_3 ="""(define (problem strips-gripper3) (:domain gripper-strips) (:objects ;; TODO etudiant : declarez les pieces, les balles et les pinces ) (:init ;; TODO etudiant : position du robot, etat des pinces, position des balles ) (:goal (and ;; TODO etudiant : l'etat but a atteindre )))"""# Une fois GRIPPER_PROBLEM_3 complete, vous pourrez le resoudre avec un# planificateur (unified-planning + OneshotPlanner) comme en section 6.4.# Question subsidiaire : avec seulement 2 pinces, combien d'actions au# minimum pour ce but reparti sur 2 pieces destination ?print("Exercice a completer")
Exercice a completer
Indice : Pour aborder les exercices
Conseils pour reussir :
Commencez par identifier les types : Quels sont les objets du problème ? (ex: bloc, lieu, robot)
Listez les predicats : Quelles proprietes sont importantes ? (ex: position, etat)
Definissez les actions : Quelles opérations sont possibles ? (preconditions + effets)
Instanciez le problème : Quels objets concrets ? Quel etat initial ? Quel but ?
Methodologie : - Dessinez l’etat initial et le but sur papier - Identifiez les actions necessaires pour passer de l’un a l’autre - Verifiez que chaque action a des preconditions realisables - Testez avec un planificateur (pyperplan est rapide)
Erreurs courantes a eviter : - Oublier de declarer un type dans :types - Confondre preconditions et effets - Oublier les effets negatifs (not ...) - Créer des actions inutiles ou redondantes
Exemple guide : Domaine Robot-Entrepot
Avant de passer a l’Exercice 9.2, voici un exemple complet de definition d’un domaine PDDL simplifie. Le contexte est proche : un robot dans un entrepot peut saisir un objet et le deposer sur une etagere.
Ce que nous allons modeliser : - 2 types : objet et etagere - 3 predicats : position de l’objet, robot libre, objet sur une etagere - 2 actions : saisir et deposer
Observez comment chaque action declare ses preconditions (conditions necessaires) et ses effets (ajouts et suppressions de predicats).
# Exemple guide : Domaine PDDL Robot-Entrepot (solution complete)ROBOT_ENTREPOT_DOMAIN ="""(define (domain robot-entrepot) (:requirements :strips :typing) (:types objet etagere - object) (:predicates ;; L'objet est dans une etagere (sur-etagere ?o - objet ?e - etagere) ;; Le robot tient un objet (tient ?o - objet) ;; Le robot a les mains libres (robot-libre) ) ;; Action : saisir un objet depuis une etagere (:action saisir :parameters (?o - objet ?e - etagere) :precondition (and (sur-etagere ?o ?e) (robot-libre)) :effect (and (tient ?o) (not (sur-etagere ?o ?e)) (not (robot-libre))) ) ;; Action : deposer un objet sur une etagere (:action deposer :parameters (?o - objet ?e - etagere) :precondition (and (tient ?o)) :effect (and (sur-etagere ?o ?e) (robot-libre) (not (tient ?o))) ))"""# Verification structurelle : compter les composantes PDDLactions = ROBOT_ENTREPOT_DOMAIN.count("(:action")predicates = ROBOT_ENTREPOT_DOMAIN.count("(") - ROBOT_ENTREPOT_DOMAIN.count("(not") # approximationprint("Domaine Robot-Entrepot defini : robot-entrepot")print(f"Actions definies : {actions} (saisir, deposer)")print()print("Action 'saisir(objet, etagere)' :")print(" Preconditions : objet sur etagere + robot libre")print(" Effets : robot tient objet + objet retire de l'etagere + robot plus libre")print()print("Action 'deposer(objet, etagere)' :")print(" Preconditions : robot tient objet")print(" Effets : objet sur etagere + robot libre + robot ne tient plus l'objet")print()print("> Chaque effet negatif (not ...) est indispensable pour que le planificateur")print(" comprenne que l'etat du monde change apres l'action.")
Domaine Robot-Entrepot defini : robot-entrepot
Actions definies : 2 (saisir, deposer)
Action 'saisir(objet, etagere)' :
Preconditions : objet sur etagere + robot libre
Effets : robot tient objet + objet retire de l'etagere + robot plus libre
Action 'deposer(objet, etagere)' :
Preconditions : robot tient objet
Effets : objet sur etagere + robot libre + robot ne tient plus l'objet
> Chaque effet negatif (not ...) est indispensable pour que le planificateur
comprenne que l'etat du monde change apres l'action.
Exercice 9.2 - Domaine PDDL Robot-Cuisine
Ecrivez un domaine PDDL pour un robot dans une cuisine.
Contexte : Un robot peut prendre un ingredient et le poser dans un plat.
Objectif : Completer la chaîne PDDL ci-dessous avec 2 actions et leurs preconditions/effets.
Indices : - # Étape 1 : Définir les types ingredient, location, plat - # Étape 2 : Action prendre : preconditions = ingredient a la location, robot libre - # Étape 3 : Action poser : preconditions = robot tient ingredient ; effets = ingredient dans le plat - # Étape 4 : Verifier la syntaxe PDDL (parentheses, types, predicats)
if UP_AVAILABLE:from unified_planning.shortcuts import*from unified_planning.engines import PlanGenerationResultStatus# TODO etudiant: definissez le domaine Gripper avec l'API unified_planning gripper_domain =None# TODO etudiantprint(f"Domaine Gripper UP: {gripper_domain}")print("Exercice a completer")
Domaine Gripper UP: None
Exercice a completer
10. Resume
Points cles
Concept
Description
PDDL
Langage standard pour la planification automatique
Domaine
Définit types, predicats et actions (reutilisable)
Problème
Définit objets, etat initial et but (spécifique)
Predicats
Proprietes/relations binaires (vrai/faux)
Actions
Transitions avec preconditions et effets
STRIPS
Modèle de base (add/delete lists)
Structure PDDL
domain.pddl problem.pddl
| |
v v
(:types ...) (:objects ...)
(:predicates ...) (:init ...)
(:action ...) (:goal ...)
Prochaines étapes
Dans le notebook suivant Planners-3-State-Space, nous explorerons : - La representation des espaces d’etats - La recherche dans un graphe d’etats - Les algorithmes de recherche (BFS, DFS, A*)
11. Conclusion
Ce notebook a couvre les fondamentaux de PDDL, le langage standard de la planification automatique.
Resume des acquis
Competence
Statut
Pratique
Lire un domaine PDDL
OK
Exemples Logistics, Gripper
Ecrire un domaine PDDL
OK
Exercices
Lire un problème PDDL
OK
Exemples Logistics, Gripper
Ecrire un problème PDDL
OK
Exercices
Modeliser avec unified-planning
OK
Exemple Logistics complet
Concepts fondamentaux
Concept
Description
Exemple
Domaine
Types, predicats, actions (reutilisable)
logistics-simple
Problème
Objets, etat initial, but (spécifique)
logistics-simple-1
Predicat
Propriete binaire (vrai/faux)
(at ?obj ?loc)
Action
Transition avec preconditions et effets
load, unload, drive
STRIPS
Modèle de base (add/delete lists)
Preconditions + effets
Prochaines étapes
Planners-3-State-Space : Comprendre comment les planificateurs explorent l’espace d’etats
Planners-4-Fast-Downward : Utiliser un planificateur industriel
Planners-5-Heuristics : Decouvrir les heuristiques pour accelerer la recherche
Point cle : PDDL separe le quoi (domaine, actions générales) du comment (problème, instance spécifique). Cette separation permet de reutiliser un domaine pour plusieurs problemes.