{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "-O38cYGqUwCJ" }, "source": [ "# PDDL I/O Example\n", "\n", "This notebook will show the possible interations between the pddl language and the unified_planning usage.\n", "\n", "[![Open In GitHub](https://img.shields.io/badge/see-Github-579aca?logo=github)](https:///github.com/aiplan4eu/unified-planning/blob/master/docs/notebooks/io/01-pddl-usage-example.ipynb)\n", "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/aiplan4eu/unified-planning/blob/master/docs/notebooks/io/01-pddl-usage-example.ipynb)\n", "\n", "## Setup\n", "We start by installing the library with PIP\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "id": "x-vPi8y9ce2y", "tags": [ "remove_from_CI" ] }, "outputs": [], "source": [ "!pip install --pre unified-planning" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sample pddl domain and problem\n", "\n", "Using wget, download from the unified_planning repository the pddl files we need for testing." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "id": "01nDJbkoVZU1" }, "outputs": [], "source": [ "!wget https://raw.githubusercontent.com/aiplan4eu/unified-planning/master/unified_planning/test/pddl/counters/domain.pddl -O /tmp/counters_domain.pddl" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "id": "-fFY3Q3mZo4P" }, "outputs": [], "source": [ "!wget https://raw.githubusercontent.com/aiplan4eu/unified-planning/master/unified_planning/test/pddl/counters/problem.pddl -O /tmp/counters_problem.pddl" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## PDDL Reader\n", "\n", "As the name suggests, the [PDDLReader](https://unified-planning.readthedocs.io/en/latest/api_ref.html#unified_planning.io.PDDLReader) offers the capability of parsing a problem from a pddl file and creates a semantically equivalent problem in the `unified_planning` framework.\n", "\n", "There are 2 possible usages:\n", "- the first one is parsing both a domain file and a problem file.\n", "- the second one is parsing only a domain file and then populate the problem using the `unified_planning` capabilities." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Parsing domain and problem files\n", "\n", "In the following example the `PDDLReader` will be used to parse a complete PDDL problem; so it will need a `domain.pddl` file and a `problem.pddl` file." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "id": "1xp1How6aClP" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "problem name = instance_4\n", "\n", "types = [counter]\n", "\n", "fluents = [\n", " real value[c=counter]\n", " real max_int\n", "]\n", "\n", "actions = [\n", " action increment(counter c) {\n", " preconditions = [\n", " ((value(c) + 1) <= max_int)\n", " ]\n", " effects = [\n", " value(c) += 1\n", " ]\n", " }\n", " action decrement(counter c) {\n", " preconditions = [\n", " (1 <= value(c))\n", " ]\n", " effects = [\n", " value(c) -= 1\n", " ]\n", " }\n", "]\n", "\n", "objects = [\n", " counter: [c0, c1, c2, c3]\n", "]\n", "\n", "initial fluents default = [\n", "]\n", "\n", "initial values = [\n", " max_int := 10\n", " value(c0) := 0\n", " value(c1) := 0\n", " value(c2) := 0\n", " value(c3) := 0\n", "]\n", "\n", "goals = [\n", " (((value(c0) + 1) <= value(c1)) and ((value(c1) + 1) <= value(c2)) and ((value(c2) + 1) <= value(c3)))\n", "]\n", "\n", "\n" ] } ], "source": [ "# Import the PDDLReader and PDDLWriter classes\n", "from unified_planning.io import PDDLReader, PDDLWriter\n", "\n", "reader = PDDLReader()\n", "pddl_problem = reader.parse_problem('/tmp/counters_domain.pddl', '/tmp/counters_problem.pddl')\n", "print(pddl_problem)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Parsing only a domain file\n", "\n", "In the following example the `PDDLReader` will be used to parse only a domain file, and then the problem will be populated using the `unified_planning` framework." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "problem name = fn-counters\n", "\n", "types = [counter]\n", "\n", "fluents = [\n", " real value[c=counter]\n", " real max_int\n", "]\n", "\n", "actions = [\n", " action increment(counter c) {\n", " preconditions = [\n", " ((value(c) + 1) <= max_int)\n", " ]\n", " effects = [\n", " value(c) += 1\n", " ]\n", " }\n", " action decrement(counter c) {\n", " preconditions = [\n", " (1 <= value(c))\n", " ]\n", " effects = [\n", " value(c) -= 1\n", " ]\n", " }\n", "]\n", "\n", "objects = [\n", " counter: [c0, c1, c2, c3, c4]\n", "]\n", "\n", "initial fluents default = [\n", "]\n", "\n", "initial values = [\n", " max_int := 10\n", " value(c0) := 0\n", " value(c1) := 0\n", " value(c2) := 0\n", " value(c3) := 0\n", " value(c4) := 0\n", "]\n", "\n", "goals = [\n", " ((value(c0) + 1) <= value(c1))\n", " ((value(c1) + 1) <= value(c2))\n", " ((value(c2) + 1) <= value(c3))\n", " ((value(c3) + 1) <= value(c4))\n", "]\n", "\n", "\n", "problem name = fn-counters\n", "\n", "types = [counter]\n", "\n", "fluents = [\n", " real value[c=counter]\n", " real max_int\n", "]\n", "\n", "actions = [\n", " action increment(counter c) {\n", " preconditions = [\n", " ((value(c) + 1) <= max_int)\n", " ]\n", " effects = [\n", " value(c) += 1\n", " ]\n", " }\n", " action decrement(counter c) {\n", " preconditions = [\n", " (1 <= value(c))\n", " ]\n", " effects = [\n", " value(c) -= 1\n", " ]\n", " }\n", "]\n", "\n", "objects = [\n", " counter: [c0, c1, c2, c3, c4, c5]\n", "]\n", "\n", "initial fluents default = [\n", "]\n", "\n", "initial values = [\n", " max_int := 10\n", " value(c0) := 0\n", " value(c1) := 0\n", " value(c2) := 0\n", " value(c3) := 0\n", " value(c4) := 0\n", " value(c5) := 0\n", "]\n", "\n", "goals = [\n", " ((value(c0) + 1) <= value(c1))\n", " ((value(c1) + 1) <= value(c2))\n", " ((value(c2) + 1) <= value(c3))\n", " ((value(c3) + 1) <= value(c4))\n", " ((value(c4) + 1) <= value(c5))\n", "]\n", "\n", "\n" ] } ], "source": [ "# Domain is a up.model.Problem that contains only the pddl domain. \n", "domain = reader.parse_problem('/tmp/counters_domain.pddl', None) # None is the default, so it can be avoided\n", "counter_type = domain.user_type(\"counter\") # get the counter type\n", "domain.set_initial_value(domain.fluent(\"max_int\"), 10) # initialize the fluent \"max_int\"\n", "value_fluent = domain.fluent(\"value\") # get the \"value\" fluent\n", "for i in range(4, 6):\n", " problem = domain.clone() # Clone the parsed domain, then populate it\n", " # Populate the problem. \"j\" iterates in [0, i], creates an object of type\n", " # \"counter\", sets it's initial value to 0, and then sets the goal:\n", " # \"value(c{j-1}) + 1 <= value(c{j})\". \n", " # This means that every value of the added objects must be\n", " # at least 1 bigger than the object added before.\n", " for j in range(i + 1):\n", " object_j = problem.add_object(f\"c{str(j)}\", counter_type) # Create and add object\n", " problem.set_initial_value(value_fluent(object_j), 0) # Set the initial value of \"value(object)\" to 0\n", " if j > 0: \n", " previous_object = problem.object(f\"c{str(j-1)}\") # Get previous object\n", " problem.add_goal( # Add the goal \"value(c{j-1})+1 <= value(c{j})\"\n", " value_fluent(previous_object)+1 <= value_fluent(object_j),\n", " )\n", " print(problem)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## PDDL Writer\n", "\n", "As the `PDDLReader` allows a unified_planning user to parse a problem from pddl, the [PDDLWriter](https://unified-planning.readthedocs.io/en/latest/api_ref.html#unified_planning.io.PDDLWriter) offers the capability of dumping a `unified_planning Problem` in pddl.\n", "\n", "There are 3 possible usages of the `PDDLWriter`:\n", "- printing pddl domain and problem to a file\n", "- getting pddl domain and problem as a python str\n", "- printing pddl domain and problem to `STDOUT`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Writing to file\n", "\n", "To write the pddl equivalent of a `unified_planning Problem` to a file we use the `PDDLWriter.write_domain` and `PDDLWriter.write_problem` methods." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "id": "s_lwgr5pVEsC" }, "outputs": [], "source": [ "w = PDDLWriter(problem)\n", "w.write_domain('/tmp/written_counters_domain.pddl')\n", "w.write_problem('/tmp/written_counters_problem.pddl')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Getting domain and problem as a python string\n", "\n", "To get the pddl equivalent of a `unified_planning Problem` as a python string we use the `PDDLWriter.get_domain` and `PDDLWriter.get_problem` methods." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(define (domain fn_counters-domain)\n", " (:requirements :strips :typing :numeric-fluents)\n", " (:types counter)\n", " (:functions (value ?c - counter) (max_int))\n", " (:action increment\n", " :parameters ( ?c - counter)\n", " :precondition (and (<= (+ 1 (value ?c)) (max_int)))\n", " :effect (and (increase (value ?c) 1)))\n", " (:action decrement\n", " :parameters ( ?c - counter)\n", " :precondition (and (<= 1 (value ?c)))\n", " :effect (and (decrease (value ?c) 1)))\n", ")\n", "\n", "(define (problem fn_counters-problem)\n", " (:domain fn_counters-domain)\n", " (:objects\n", " c0 c1 c2 c3 c4 c5 - counter\n", " )\n", " (:init (= (max_int) 10) (= (value c0) 0) (= (value c1) 0) (= (value c2) 0) (= (value c3) 0) (= (value c4) 0) (= (value c5) 0))\n", " (:goal (and (<= (+ 1 (value c0)) (value c1)) (<= (+ 1 (value c1)) (value c2)) (<= (+ 1 (value c2)) (value c3)) (<= (+ 1 (value c3)) (value c4)) (<= (+ 1 (value c4)) (value c5))))\n", ")\n", "\n" ] } ], "source": [ "print(w.get_domain())\n", "print(w.get_problem())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Printing domain and problem to STDOUT\n", "\n", "To print the pddl equivalent of a `unified_planning Problem` to `STDOUT` we use the `PDDLWriter.print_domain` and `PDDLWriter.print_problem` methods." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(define (domain fn_counters-domain)\n", " (:requirements :strips :typing :numeric-fluents)\n", " (:types counter)\n", " (:functions (value ?c - counter) (max_int))\n", " (:action increment\n", " :parameters ( ?c - counter)\n", " :precondition (and (<= (+ 1 (value ?c)) (max_int)))\n", " :effect (and (increase (value ?c) 1)))\n", " (:action decrement\n", " :parameters ( ?c - counter)\n", " :precondition (and (<= 1 (value ?c)))\n", " :effect (and (decrease (value ?c) 1)))\n", ")\n", "(define (problem fn_counters-problem)\n", " (:domain fn_counters-domain)\n", " (:objects\n", " c0 c1 c2 c3 c4 c5 - counter\n", " )\n", " (:init (= (max_int) 10) (= (value c0) 0) (= (value c1) 0) (= (value c2) 0) (= (value c3) 0) (= (value c4) 0) (= (value c5) 0))\n", " (:goal (and (<= (+ 1 (value c0)) (value c1)) (<= (+ 1 (value c1)) (value c2)) (<= (+ 1 (value c2)) (value c3)) (<= (+ 1 (value c3)) (value c4)) (<= (+ 1 (value c4)) (value c5))))\n", ")\n" ] } ], "source": [ "w.print_domain()\n", "w.print_problem()" ] } ], "metadata": { "celltoolbar": "Tags", "colab": { "collapsed_sections": [], "name": "PDDL Usage example", "provenance": [] }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12" }, "vscode": { "interpreter": { "hash": "fcfc934ecfdac8ddac62d6a80ba8d82faf47dc8d54fd6a313f0c016b85ebec0e" } } }, "nbformat": 4, "nbformat_minor": 4 }