From df75be713f069acb32ead99072667081fb165d31 Mon Sep 17 00:00:00 2001 From: Arthur Bit-Monnot Date: Wed, 11 Oct 2023 10:42:58 +0200 Subject: [PATCH 1/7] doc: Update hierarchical planning notebook --- docs/notebooks/07-hierrachical-planning.ipynb | 876 +++++++++++++++--- 1 file changed, 746 insertions(+), 130 deletions(-) diff --git a/docs/notebooks/07-hierrachical-planning.ipynb b/docs/notebooks/07-hierrachical-planning.ipynb index 06772e5f4..a75953fad 100644 --- a/docs/notebooks/07-hierrachical-planning.ipynb +++ b/docs/notebooks/07-hierrachical-planning.ipynb @@ -3,32 +3,40 @@ { "cell_type": "markdown", "metadata": { - "id": "6nOTljC_mTMn" + "id": "6nOTljC_mTMn", + "slideshow": { + "slide_type": "slide" + } }, "source": [ "# Hierarchical Planning\n", "\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/07-hierrachical-planning.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/07-hierrachical-planning.ipynb)\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/07-hierarchical-planning.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/07-hierarchical-planning.ipynb)" ] }, { "cell_type": "markdown", "metadata": { - "id": "t8dCcpf7mivV" + "id": "t8dCcpf7mivV", + "slideshow": { + "slide_type": "slide" + } }, "source": [ "## Setup\n", "\n", - "We start by installing the unified planning library and a hierarchical planner (aries)." + "We start by downloading (from github) the unified planning library and a hierarchical planner (aries)." ] }, { "cell_type": "code", - "execution_count": 53, + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.277967428Z", + "start_time": "2023-07-07T08:26:01.671820250Z" + }, "id": "BoqALxJWdfl8", "tags": [ "remove_from_CI" @@ -36,46 +44,35 @@ }, "outputs": [], "source": [ - "%pip install --pre unified-planning\n", - "%pip install up-aries" + "%pip install unified-planning[aries]\n", + "\n", + "import unified_planning as up\n", + "from unified_planning.shortcuts import *\n", + "from unified_planning.model.htn import *" ] }, { "cell_type": "markdown", "metadata": { - "id": "9dP5scv7nNJu" + "slideshow": { + "slide_type": "slide" + } }, "source": [ - "## Demo\n", - "\n", - "In this demo, we show how to model a hierrachical planning problem using the Unified Planning Library.\n", - "\n", - "### Specifyng a (flat) planning problem \n", + "## Case study: Logistics problem (IPC 1998)\n", "\n", - "#### Basic imports\n", - "The basic imports we need for this demo are abstracted in the `shortcuts` and `htn` packages." + "![logistics](https://homepages.laas.fr/abitmonnot/files/img/logistics.png)\n", + "\n" ] }, { - "cell_type": "code", - "execution_count": 55, + "cell_type": "markdown", "metadata": { - "id": "06rETnGAfQHg" + "slideshow": { + "slide_type": "skip" + } }, - "outputs": [], "source": [ - "import unified_planning\n", - "from unified_planning.shortcuts import *\n", - "from unified_planning.model.htn import *\n", - "import unified_planning as up" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Logistics problem\n", - "\n", "For this example, we are interested in *logistics* problem where the objective is to move packages from one location to another. Packages can be transported by truck between two locations in the same city, or by airplane between two airport locations in two distinct cities.\n", "\n", "\n", @@ -86,82 +83,305 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 2, "metadata": { - "id": "huAy2IbVn0GZ" + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.318700483Z", + "start_time": "2023-07-07T08:26:03.314367160Z" + }, + "id": "huAy2IbVn0GZ", + "slideshow": { + "slide_type": "slide" + } }, "outputs": [], "source": [ - "pb = HierarchicalProblem() # the only line that is specific to hierarchical planning in this code block\n", + "#pb = Problem() # for a non-hierarchical problem\n", + "pb = HierarchicalProblem() # make it hierarchical instead\n", + "\n", + "Package = UserType(\"Package\")\n", "\n", "PackageLoc = UserType(\"PackageLoc\")\n", "Loc = UserType(\"Location\", father=PackageLoc)\n", "Airport = UserType(\"Airport\", father=Loc)\n", "City = UserType(\"City\")\n", + "\n", "Vehicle = UserType(\"Vehicle\", father=PackageLoc)\n", "Truck = UserType(\"Truck\", father=Vehicle)\n", - "Airplane = UserType(\"Airplane\", father=Vehicle)\n", - "Package = UserType(\"Package\")\n", + "Airplane = UserType(\"Airplane\", father=Vehicle)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.318700483Z", + "start_time": "2023-07-07T08:26:03.314367160Z" + }, + "id": "huAy2IbVn0GZ", + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "types = [City, PackageLoc, Location - PackageLoc, Package, Vehicle - PackageLoc]\n", + "\n", + "fluents = [\n", + " City city[of=Location - PackageLoc]\n", + " PackageLoc loc[package=Package]\n", + " Location - PackageLoc at[vehicle=Vehicle - PackageLoc]\n", + "]\n", + "\n", + "actions = [\n", + "]\n", + "\n", + "objects = [\n", + " City: []\n", + " PackageLoc: []\n", + " Location - PackageLoc: []\n", + " Package: []\n", + " Vehicle - PackageLoc: []\n", + "]\n", + "\n", + "initial fluents default = [\n", + "]\n", + "\n", + "initial values = [\n", + "]\n", + "\n", + "goals = [\n", + "]\n", + "\n", + "abstract tasks = [\n", + "]\n", + "\n", + "methods = [\n", + "]\n", + "\n", + "task network {\n", + " subtasks = [\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "# city of location\n", + "city = pb.add_fluent(\"city\", City, of=Loc) \n", "\n", - "city = pb.add_fluent(\"city\", City, of=Loc)\n", + "# current location of package / vehicle\n", "loc = pb.add_fluent(\"loc\", PackageLoc, package=Package)\n", "at = pb.add_fluent(\"at\", Loc, vehicle=Vehicle)\n", - "\n", + "print(pb)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.318700483Z", + "start_time": "2023-07-07T08:26:03.314367160Z" + }, + "id": "huAy2IbVn0GZ", + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# city1 with a location and an airport\n", "city1 = pb.add_object(\"city1\", City)\n", "loc1 = pb.add_object(\"loc1\", Loc)\n", "pb.set_initial_value(city(loc1), city1)\n", "airport1 = pb.add_object(\"airport1\", Airport)\n", "pb.set_initial_value(city(airport1), city1)\n", "\n", + "# city2 with one location and an airport\n", "city2 = pb.add_object(\"city2\", City)\n", "loc2 = pb.add_object(\"loc2\", Loc)\n", "pb.set_initial_value(city(loc2), city2)\n", "airport2 = pb.add_object(\"airport2\", Airport)\n", - "pb.set_initial_value(city(airport2), city2)\n", - "\n", + "pb.set_initial_value(city(airport2), city2)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.318700483Z", + "start_time": "2023-07-07T08:26:03.314367160Z" + }, + "id": "huAy2IbVn0GZ", + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ "truck1 = pb.add_object(\"truck1\", Truck)\n", "pb.set_initial_value(at(truck1), loc1)\n", "\n", "package1 = pb.add_object(\"package1\", Package)\n", "pb.set_initial_value(loc(package1), airport1)\n", "package2 = pb.add_object(\"package2\", Package)\n", - "pb.set_initial_value(loc(package2), loc1)\n", - "\n", + "pb.set_initial_value(loc(package2), loc1)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.318700483Z", + "start_time": "2023-07-07T08:26:03.314367160Z" + }, + "id": "huAy2IbVn0GZ", + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "action load(Package package, Vehicle - PackageLoc vehicle, Location - PackageLoc l) {\n", + " preconditions = [\n", + " (at(vehicle) == l)\n", + " (loc(package) == l)\n", + " ]\n", + " effects = [\n", + " loc(package) := vehicle\n", + " ]\n", + " }\n", + "action unload(Package package, Vehicle - PackageLoc vehicle, Location - PackageLoc l) {\n", + " preconditions = [\n", + " (at(vehicle) == l)\n", + " (loc(package) == vehicle)\n", + " ]\n", + " effects = [\n", + " loc(package) := l\n", + " ]\n", + " }\n" + ] + } + ], + "source": [ "load = InstantaneousAction(\"load\", package=Package, vehicle=Vehicle, l=Loc)\n", "load.add_precondition(Equals(at(load.vehicle), load.l))\n", "load.add_precondition(Equals(loc(load.package), load.l))\n", "load.add_effect(loc(load.package), load.vehicle) # package now in vehicle\n", "pb.add_action(load)\n", + "print(load)\n", "\n", "unload = InstantaneousAction(\"unload\", package=Package, vehicle=Vehicle, l=Loc)\n", "unload.add_precondition(Equals(at(unload.vehicle), unload.l))\n", "unload.add_precondition(Equals(loc(unload.package), unload.vehicle))\n", "unload.add_effect(loc(unload.package), unload.l)\n", "pb.add_action(unload)\n", - "\n", + "print(unload)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.318700483Z", + "start_time": "2023-07-07T08:26:03.314367160Z" + }, + "id": "huAy2IbVn0GZ", + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "action move(Truck - Vehicle truck, Location - PackageLoc src, Location - PackageLoc tgt) {\n", + " preconditions = [\n", + " (city(src) == city(tgt))\n", + " (at(truck) == src)\n", + " ]\n", + " effects = [\n", + " at(truck) := tgt\n", + " ]\n", + " }\n", + "action fly-plane(Airplane - Vehicle plane, Airport - Location src, Airport - Location tgt) {\n", + " preconditions = [\n", + " (at(plane) == src)\n", + " ]\n", + " effects = [\n", + " at(plane) := tgt\n", + " ]\n", + " }\n" + ] + } + ], + "source": [ "move = InstantaneousAction(\"move\", truck=Truck, src=Loc, tgt=Loc)\n", "move.add_precondition(Equals(city(move.src), city(move.tgt)))\n", "move.add_precondition(Equals(at(move.truck), move.src))\n", "move.add_effect(at(move.truck), move.tgt)\n", "pb.add_action(move)\n", + "print(move)\n", "\n", "fly_plane = InstantaneousAction(\"fly-plane\", plane=Airplane, src=Airport, tgt=Airport)\n", "fly_plane.add_precondition(Equals(at(fly_plane.plane), fly_plane.src))\n", "fly_plane.add_effect(at(fly_plane.plane), fly_plane.tgt)\n", - "pb.add_action(fly_plane)" + "pb.add_action(fly_plane)\n", + "print(fly_plane)" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, "source": [ "If we now create and solve a new version of problem with a trivial goal statement:" ] }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 8, "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.369134769Z", + "start_time": "2023-07-07T08:26:03.314575334Z" + }, + "id": "LZUgad7ZoA2p" + }, + "outputs": [], + "source": [ + "# helper function that just invokes a planner and prints the plan\n", + "def solve(pb: Problem, verbose=False): \n", + " result = OneshotPlanner(problem_kind=pb.kind).solve(pb)\n", + " if result.plan is not None:\n", + " print(\"Plan:\", repr(result.plan) if verbose else str(result.plan))\n", + " else:\n", + " print(result.status)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.369134769Z", + "start_time": "2023-07-07T08:26:03.314575334Z" + }, "id": "LZUgad7ZoA2p" }, "outputs": [ @@ -169,14 +389,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "Plan: None\n" + "PlanGenerationResultStatus.UNSOLVABLE_INCOMPLETELY\n" ] } ], "source": [ - "def solve(pb: HierarchicalProblem): # helper function that just invokes a planner and prints the plan\n", - " print(\"Plan:\", OneshotPlanner(problem_kind=pb.kind).solve(pb).plan)\n", - "\n", "pb_clone = pb.clone()\n", "pb_clone.add_goal(Equals(at(truck1), airport1))\n", "solve(pb_clone)" @@ -185,10 +402,13 @@ { "cell_type": "markdown", "metadata": { - "id": "rVzqSj3XoDPa" + "id": "rVzqSj3XoDPa", + "slideshow": { + "slide_type": "skip" + } }, "source": [ - "The planner tells us that there is no solution to this problem. This might be surprising as a single `move(truck1, loc1, airport1)` action would have worked to bring the truck to its objective.\n", + "The planner tells us that there is **no solution to this problem**. This might be surprising as a single `move(truck1, loc1, airport1)` action would have worked to bring the truck to its objective.\n", "\n", "This highlights the most important difference between hierarchical and non-hierarchical planning.\n", "In hierarchical planning, all actions of the plan must derive from high-level *objective tasks*.\n", @@ -198,17 +418,29 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, "source": [ "### Tasks and Methods\n", "\n", - "Let us define our first task `bring-truck(truck, to)`:" + "Let us define our first task `bring-truck(truck, dest)`:" ] }, { "cell_type": "code", - "execution_count": 58, - "metadata": {}, + "execution_count": 10, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.369444377Z", + "start_time": "2023-07-07T08:26:03.358334675Z" + }, + "slideshow": { + "slide_type": "-" + } + }, "outputs": [], "source": [ "# Task representing the objective of getting a given truck to a particular location\n", @@ -217,7 +449,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, "source": [ "Conceptually, a task captures an objective to be achieved. In our case, its captures the objective of bringing a `truck` to a given `destination`, both `truck` and `destination` being parameters of the task.\n", "\n", @@ -231,74 +467,311 @@ "We define one `Method` for each such recipe:" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "\n", + "![Bring truck](https://homepages.laas.fr/abitmonnot/files/img/bring-truck.png)" + ] + }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 11, "metadata": { - "id": "dRfrnEOfoHD8" + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.369756021Z", + "start_time": "2023-07-07T08:26:03.358476153Z" + }, + "id": "dRfrnEOfoHD8", + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# Option 1: truck already at destination location, nothing to do\n", + "m = Method(\"bring-truck-noop\", truck=Truck, dest=Loc)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.369756021Z", + "start_time": "2023-07-07T08:26:03.358476153Z" + }, + "id": "dRfrnEOfoHD8", + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# declares that m achieves the `bring-truck(truck, dest)` task`\n", + "m.set_task(bring_truck, m.truck, m.dest) " + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.369756021Z", + "start_time": "2023-07-07T08:26:03.358476153Z" + }, + "id": "dRfrnEOfoHD8", + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# only usable if the truck is already at the right location\n", + "# no subtasks, implying that if the method is usable, there is nothing left to do\n", + "m.add_precondition(Equals(at(m.truck), m.dest)) " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.369756021Z", + "start_time": "2023-07-07T08:26:03.358476153Z" + }, + "id": "dRfrnEOfoHD8", + "slideshow": { + "slide_type": "fragment" + } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "method bring-truck-noop(Truck - Vehicle truck, Location - PackageLoc to) {\n", - " task = bring-truck(Truck - Vehicle truck, Location - PackageLoc to)\n", + "method bring-truck-noop(Truck - Vehicle truck, Location - PackageLoc dest) {\n", + " task = bring-truck(Truck - Vehicle truck, Location - PackageLoc dest)\n", " preconditions = [\n", - " (at(truck) == to)\n", - " ]\n", - "}\n", - "method bring-truck-move(Truck - Vehicle truck, Location - PackageLoc orig, Location - PackageLoc to) {\n", - " task = bring-truck(Truck - Vehicle truck, Location - PackageLoc to)\n", - " preconditions = [\n", - " (at(truck) == orig)\n", - " (not (orig == to))\n", - " (city(orig) == city(to))\n", - " ]\n", - " subtasks = [\n", - " _t45: move(truck, orig, to)\n", + " (at(truck) == dest)\n", " ]\n", "}\n" ] } ], "source": [ - "# Option 1: truck already at target location, nothing to do\n", - "m = Method(\"bring-truck-noop\", truck=Truck, to=Loc)\n", - "m.set_task(bring_truck, m.truck, m.to) # declares that m achieves the `bring-truck(truck, to)` task`\n", - "m.add_precondition(Equals(at(m.truck), m.to)) # only usable if the truck is already at the right location\n", - "# no subtasks, implying that if the method is usable, there is nothing left to do\n", - "pb.add_method(m)\n", - "print(m)\n", - "\n", - "# Option 2: truck not at target location, move it\n", - "m = Method(\"bring-truck-move\", truck=Truck, orig=Loc, to=Loc)\n", - "m.set_task(bring_truck, m.truck, m.to) # declares that m achieves the `bring-truck(truck, to)` task`\n", - "m.add_precondition(Equals(at(m.truck), m.orig)) # restrict applicability to cases where the truck is \n", - "m.add_precondition(Not(Equals(m.orig, m.to))) # in a different location \n", - "m.add_precondition(Equals(city(m.orig), city(m.to))) # of the same city\n", - "m.add_subtask(move, m.truck, m.orig, m.to) # accomplishing this method requires executing a `move` action\n", "pb.add_method(m)\n", "print(m)" ] }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.369993732Z", + "start_time": "2023-07-07T08:26:03.358552246Z" + }, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# Option 2: truck not at target location, move it\n", + "m = Method(\"bring-truck-move\", truck=Truck, orig=Loc, dest=Loc)\n", + "# declares that m achieves the `bring-truck(truck, to)` task`\n", + "m.set_task(bring_truck, m.truck, m.dest) " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.369993732Z", + "start_time": "2023-07-07T08:26:03.358552246Z" + }, + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "m.add_precondition(Equals(at(m.truck), m.orig)) # restrict applicability to cases where the truck is\n", + "m.add_precondition(Not(Equals(m.orig, m.dest))) # in a different location\n", + "m.add_precondition(Equals(city(m.orig), city(m.dest))) # of the same city" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# accomplishing this method requires executing a `move` action\n", + "m.add_subtask(move, m.truck, m.orig, m.dest, ident=\"move-subtask\") \n", + "\n", + "pb.add_method(m)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "scrolled": true, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "types = [City, PackageLoc, Location - PackageLoc, Package, Vehicle - PackageLoc, Airport - Location, Truck - Vehicle, Airplane - Vehicle]\n", + "\n", + "fluents = [\n", + " City city[of=Location - PackageLoc]\n", + " PackageLoc loc[package=Package]\n", + " Location - PackageLoc at[vehicle=Vehicle - PackageLoc]\n", + "]\n", + "\n", + "actions = [\n", + " action load(Package package, Vehicle - PackageLoc vehicle, Location - PackageLoc l) {\n", + " preconditions = [\n", + " (at(vehicle) == l)\n", + " (loc(package) == l)\n", + " ]\n", + " effects = [\n", + " loc(package) := vehicle\n", + " ]\n", + " }\n", + " action unload(Package package, Vehicle - PackageLoc vehicle, Location - PackageLoc l) {\n", + " preconditions = [\n", + " (at(vehicle) == l)\n", + " (loc(package) == vehicle)\n", + " ]\n", + " effects = [\n", + " loc(package) := l\n", + " ]\n", + " }\n", + " action move(Truck - Vehicle truck, Location - PackageLoc src, Location - PackageLoc tgt) {\n", + " preconditions = [\n", + " (city(src) == city(tgt))\n", + " (at(truck) == src)\n", + " ]\n", + " effects = [\n", + " at(truck) := tgt\n", + " ]\n", + " }\n", + " action fly-plane(Airplane - Vehicle plane, Airport - Location src, Airport - Location tgt) {\n", + " preconditions = [\n", + " (at(plane) == src)\n", + " ]\n", + " effects = [\n", + " at(plane) := tgt\n", + " ]\n", + " }\n", + "]\n", + "\n", + "objects = [\n", + " City: [city1, city2]\n", + " PackageLoc: [loc1, airport1, loc2, airport2, truck1]\n", + " Location - PackageLoc: [loc1, airport1, loc2, airport2]\n", + " Package: [package1, package2]\n", + " Vehicle - PackageLoc: [truck1]\n", + " Airport - Location: [airport1, airport2]\n", + " Truck - Vehicle: [truck1]\n", + " Airplane - Vehicle: []\n", + "]\n", + "\n", + "initial fluents default = [\n", + "]\n", + "\n", + "initial values = [\n", + " city(loc1) := city1\n", + " city(airport1) := city1\n", + " city(loc2) := city2\n", + " city(airport2) := city2\n", + " at(truck1) := loc1\n", + " loc(package1) := airport1\n", + " loc(package2) := loc1\n", + "]\n", + "\n", + "goals = [\n", + "]\n", + "\n", + "abstract tasks = [\n", + " bring-truck[truck=Truck - Vehicle, destination=Location - PackageLoc]\n", + "]\n", + "\n", + "methods = [\n", + " method bring-truck-noop(Truck - Vehicle truck, Location - PackageLoc dest) {\n", + " task = bring-truck(Truck - Vehicle truck, Location - PackageLoc dest)\n", + " preconditions = [\n", + " (at(truck) == dest)\n", + " ]\n", + " }\n", + " method bring-truck-move(Truck - Vehicle truck, Location - PackageLoc orig, Location - PackageLoc dest) {\n", + " task = bring-truck(Truck - Vehicle truck, Location - PackageLoc dest)\n", + " preconditions = [\n", + " (at(truck) == orig)\n", + " (not (orig == dest))\n", + " (city(orig) == city(dest))\n", + " ]\n", + " subtasks = [\n", + " move-subtask: move(truck, orig, dest)\n", + " ]\n", + " }\n", + "]\n", + "\n", + "task network {\n", + " subtasks = [\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "print(pb)" + ] + }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, "source": [ "Now let's try to solve this problem. Recall that curently, it has no objectives." ] }, { "cell_type": "code", - "execution_count": 60, - "metadata": {}, + "execution_count": 19, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.447951312Z", + "start_time": "2023-07-07T08:26:03.358638957Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Plan: []\n" + "Plan: Hiearchical TimeTriggeredPlan:\n" ] } ], @@ -309,7 +782,10 @@ { "cell_type": "markdown", "metadata": { - "id": "iMuggWWioJ8K" + "id": "iMuggWWioJ8K", + "slideshow": { + "slide_type": "skip" + } }, "source": [ "We get an empty plan which is what we expected as the problem specifies no objectives.\n", @@ -321,29 +797,42 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 20, "metadata": { - "id": "pgrJOj6ioMSC" + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.448372725Z", + "start_time": "2023-07-07T08:26:03.402594258Z" + }, + "id": "pgrJOj6ioMSC", + "scrolled": true, + "slideshow": { + "slide_type": "slide" + } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Plan: [move(truck1, loc1, airport1)]\n" + "Plan: Hiearchical SequentialPlan:\n", + " move(truck1, loc1, airport1)\n" ] } ], "source": [ "pb_clone = pb.clone()\n", "pb_clone.task_network.add_subtask(bring_truck(truck1, airport1))\n", + "\n", "solve(pb_clone)" ] }, { "cell_type": "markdown", "metadata": { - "id": "35A3dp--oOOS" + "id": "35A3dp--oOOS", + "slideshow": { + "slide_type": "skip" + } }, "source": [ "We now get a plan with a single `move` action. Which the only possible plan for this problem.\n", @@ -359,16 +848,23 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 21, "metadata": { - "id": "jbwJbJv8oQ9B" + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.448945016Z", + "start_time": "2023-07-07T08:26:03.402954723Z" + }, + "id": "jbwJbJv8oQ9B", + "slideshow": { + "slide_type": "slide" + } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Plan: []\n" + "Plan: Hiearchical TimeTriggeredPlan:\n" ] } ], @@ -381,39 +877,99 @@ { "cell_type": "markdown", "metadata": { - "id": "L-MnST4ioTKo" + "id": "L-MnST4ioTKo", + "slideshow": { + "slide_type": "slide" + } }, "source": [ "### Going up the hierarchy\n", "\n", "Now that we have our first task `bring-truck` that allows moving trucks in cities we can leverage it to define a more complex one: transporting packages from one location to another.\n", - "\n" + "\n", + "![Transport](https://homepages.laas.fr/abitmonnot/files/img/transport.png)\n" ] }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 22, "metadata": { - "id": "t7jLGJ1xoVxq" + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.449316846Z", + "start_time": "2023-07-07T08:26:03.432375118Z" + }, + "id": "t7jLGJ1xoVxq", + "slideshow": { + "slide_type": "-" + } }, "outputs": [], "source": [ "# Task for transporting a given package to a given location,\n", "# This method assumes that the package is already in the right city\n", - "transport_in_city = pb.add_task(\"transport-in-city\", package=Package, destination=Loc)\n", - "\n", + "transport_in_city = pb.add_task(\"transport-in-city\", package=Package, destination=Loc)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.449316846Z", + "start_time": "2023-07-07T08:26:03.432375118Z" + }, + "id": "t7jLGJ1xoVxq", + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ "# Method 1: handling the case where the package is already at the destination\n", "m = Method(\"transport-in-city-noop\", package=Package, to=Loc)\n", "m.set_task(transport_in_city, m.package, m.to) # set the task that this method achieve\n", "m.add_precondition(Equals(loc(m.package), m.to)) # only allow using this method if the package is already at the destination\n", "# note: no subtasks are added => nothing to do in this method\n", - "pb.add_method(m)\n", - "\n", + "pb.add_method(m)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.449316846Z", + "start_time": "2023-07-07T08:26:03.432375118Z" + }, + "id": "t7jLGJ1xoVxq", + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ "m = Method(\"transport-in-city-truck\", package=Package, orig=Loc, to=Loc, truck=Truck)\n", "m.set_task(transport_in_city, m.package, m.to)\n", "m.add_precondition(Equals(loc(m.package), m.orig)) # package is at origin\n", "m.add_precondition(Not(Equals(m.orig, m.to)))\n", - "m.add_precondition(Equals(city(m.orig), city(m.to))) # destination is the same city\n", + "m.add_precondition(Equals(city(m.orig), city(m.to))) # destination is the same city" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.449316846Z", + "start_time": "2023-07-07T08:26:03.432375118Z" + }, + "id": "t7jLGJ1xoVxq", + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ "# this method decomposed into a sequence of 4 subtasks (mixing the load/unload action and the 'bring-truck' task)\n", "t1 = m.add_subtask(bring_truck, m.truck, m.orig) # bring truck to package location\n", "t2 = m.add_subtask(load, m.package, m.truck, m.orig) # load package in truck\n", @@ -426,7 +982,10 @@ { "cell_type": "markdown", "metadata": { - "id": "re1sYZHKoYx5" + "id": "re1sYZHKoYx5", + "slideshow": { + "slide_type": "slide" + } }, "source": [ "Finally we set the objective of the problem, here transporting `package1` to `loc1`." @@ -434,8 +993,12 @@ }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 26, "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.521398297Z", + "start_time": "2023-07-07T08:26:03.438698913Z" + }, "id": "4zKqcGHlocdY" }, "outputs": [ @@ -443,7 +1006,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "Plan: [move(truck1, loc1, airport1), load(package1, truck1, airport1), move(truck1, airport1, loc1), unload(package1, truck1, loc1)]\n" + "Plan: Hiearchical SequentialPlan:\n", + " move(truck1, loc1, airport1)\n", + " load(package1, truck1, airport1)\n", + " move(truck1, airport1, loc1)\n", + " unload(package1, truck1, loc1)\n" ] } ], @@ -455,21 +1022,36 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, "source": [ "We can of course define multiple objectives for different packages." ] }, { "cell_type": "code", - "execution_count": 65, - "metadata": {}, + "execution_count": 27, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.533219405Z", + "start_time": "2023-07-07T08:26:03.490224379Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Plan: [load(package2, truck1, loc1), move(truck1, loc1, airport1), load(package1, truck1, airport1), unload(package2, truck1, airport1), move(truck1, airport1, loc1), unload(package1, truck1, loc1)]\n" + "Plan: Hiearchical SequentialPlan:\n", + " load(package2, truck1, loc1)\n", + " move(truck1, loc1, airport1)\n", + " load(package1, truck1, airport1)\n", + " unload(package2, truck1, airport1)\n", + " move(truck1, airport1, loc1)\n", + " unload(package1, truck1, loc1)\n" ] } ], @@ -483,18 +1065,25 @@ { "cell_type": "markdown", "metadata": { - "id": "OTDDF5M1oezl" + "id": "OTDDF5M1oezl", + "slideshow": { + "slide_type": "slide" + } }, "source": [ - "In the above problem the planner may achieve both tasks in an arbitrary order. Just like we restricted the order of tasks in methods, we can also restrict them in the initial task network.\n", + "Currently tasks may be achieved in an **arbitrary order**. Just like we restricted the order of tasks in methods, we can also restrict them in the initial task network.\n", "\n", "For instance, we could force `package1` to be handled before `package2`:" ] }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 28, "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.575363573Z", + "start_time": "2023-07-07T08:26:03.530770930Z" + }, "id": "8FTO4AoTojko" }, "outputs": [ @@ -502,7 +1091,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "Plan: [move(truck1, loc1, airport1), load(package1, truck1, airport1), move(truck1, airport1, loc1), unload(package1, truck1, loc1), load(package2, truck1, loc1), move(truck1, loc1, airport1), unload(package2, truck1, airport1)]\n" + "Plan: Hiearchical SequentialPlan:\n", + " move(truck1, loc1, airport1)\n", + " load(package1, truck1, airport1)\n", + " move(truck1, airport1, loc1)\n", + " unload(package1, truck1, loc1)\n", + " load(package2, truck1, loc1)\n", + " move(truck1, loc1, airport1)\n", + " unload(package2, truck1, airport1)\n" ] } ], @@ -517,7 +1113,10 @@ { "cell_type": "markdown", "metadata": { - "id": "Q-Pju4K2q_bM" + "id": "Q-Pju4K2q_bM", + "slideshow": { + "slide_type": "slide" + } }, "source": [ "We could also require that `package1` be first transported to `loc1` and then back to `airport1`." @@ -525,8 +1124,12 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 29, "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.623184318Z", + "start_time": "2023-07-07T08:26:03.574925362Z" + }, "id": "wuTcp_xTxvTj" }, "outputs": [ @@ -534,7 +1137,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "Plan: [move(truck1, loc1, airport1), load(package1, truck1, airport1), move(truck1, airport1, loc1), unload(package1, truck1, loc1), load(package1, truck1, loc1), move(truck1, loc1, airport1), unload(package1, truck1, airport1)]\n" + "Plan: Hiearchical SequentialPlan:\n", + " move(truck1, loc1, airport1)\n", + " load(package1, truck1, airport1)\n", + " move(truck1, airport1, loc1)\n", + " unload(package1, truck1, loc1)\n", + " load(package1, truck1, loc1)\n", + " move(truck1, loc1, airport1)\n", + " unload(package1, truck1, airport1)\n" ] } ], @@ -548,16 +1158,22 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, "source": [ "### Going further\n", "\n", - "Possible exercise: create the task and methods necessary to transport a package between two cities." + "- create the task and methods necessary to transport a package between two cities.\n", + "- Make actions durative\n", + "- Add optimality metrics (action costs, makespan, ...)" ] } ], "metadata": { - "celltoolbar": "Tags", + "celltoolbar": "Slideshow", "colab": { "collapsed_sections": [], "name": "UP Hierarchical Planning", @@ -578,7 +1194,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.6" + "version": "3.10.12" }, "vscode": { "interpreter": { From 739b16cab8602ec8ab7c1d611359219b0acb410e Mon Sep 17 00:00:00 2001 From: Arthur Bit-Monnot Date: Wed, 11 Oct 2023 10:45:59 +0200 Subject: [PATCH 2/7] doc: Fix typo hierrarchical -> hierarchical --- docs/examples.rst | 8 ++++---- ...ical-planning.ipynb => 07-hierarchical-planning.ipynb} | 0 docs/notebooks/engines/README.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename docs/notebooks/{07-hierrachical-planning.ipynb => 07-hierarchical-planning.ipynb} (100%) diff --git a/docs/examples.rst b/docs/examples.rst index c4b1d016c..2808c29dd 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -170,21 +170,21 @@ Oversubscription Planning and MetaEngine Usage In this notebook we define an oversubscription planning problem and we solve it using a ``MetaEngine``. -Hierrachical Planning +Hierarchical Planning --------------------- .. image:: https://img.shields.io/badge/see-Github-579aca?logo=github - :target: https:///github.com/aiplan4eu/unified-planning/blob/master/docs/notebooks/07-hierrachical-planning.ipynb + :target: https:///github.com/aiplan4eu/unified-planning/blob/master/docs/notebooks/07-hierarchical-planning.ipynb :alt: Open In GitHub .. image:: https://colab.research.google.com/assets/colab-badge.svg - :target: https://colab.research.google.com/github/aiplan4eu/unified-planning/blob/master/docs/notebooks/07-hierrachical-planning.ipynb + :target: https://colab.research.google.com/github/aiplan4eu/unified-planning/blob/master/docs/notebooks/07-hierarchical-planning.ipynb :alt: Open In Colab -In this notebook, we show how to use unified planning library to define hierrachical planning problem. +In this notebook, we show how to use unified planning library to define hierarchical planning problem. Sequential Simulator diff --git a/docs/notebooks/07-hierrachical-planning.ipynb b/docs/notebooks/07-hierarchical-planning.ipynb similarity index 100% rename from docs/notebooks/07-hierrachical-planning.ipynb rename to docs/notebooks/07-hierarchical-planning.ipynb diff --git a/docs/notebooks/engines/README.md b/docs/notebooks/engines/README.md index 809063bd1..e920a0839 100644 --- a/docs/notebooks/engines/README.md +++ b/docs/notebooks/engines/README.md @@ -45,9 +45,9 @@ Multi-agent Planning Refinement Planning ------------------- -- In this notebook, we show how to use unified planning library to define hierrachical planning problem. +- In this notebook, we show how to use unified planning library to define hierarchical planning problem. - [![Open In GitHub](https://img.shields.io/badge/see-Github-579aca?logo=github)](https:///github.com/aiplan4eu/unified-planning/blob/master/docs/notebooks/07-hierrachical-planning.ipynb) [![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/07-hierrachical-planning.ipynb) + [![Open In GitHub](https://img.shields.io/badge/see-Github-579aca?logo=github)](https:///github.com/aiplan4eu/unified-planning/blob/master/docs/notebooks/07-hierarchical-planning.ipynb) [![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/07-hierarchical-planning.ipynb) Combined Task and Motion Planning From 37d51249d8f69436f0752009d25a4deb184b55ef Mon Sep 17 00:00:00 2001 From: Arthur Bit-Monnot Date: Wed, 11 Oct 2023 11:31:52 +0200 Subject: [PATCH 3/7] doc: add scheduling notebook --- docs/notebooks/13-scheduling.ipynb | 475 +++++++++++++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 docs/notebooks/13-scheduling.ipynb diff --git a/docs/notebooks/13-scheduling.ipynb b/docs/notebooks/13-scheduling.ipynb new file mode 100644 index 000000000..5932ce70f --- /dev/null +++ b/docs/notebooks/13-scheduling.ipynb @@ -0,0 +1,475 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "6nOTljC_mTMn", + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Hierarchical Planning\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "t8dCcpf7mivV", + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Setup\n", + "\n", + "We start by downloading (from github) the unified planning library." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.277967428Z", + "start_time": "2023-07-07T08:26:01.671820250Z" + }, + "id": "BoqALxJWdfl8", + "tags": [ + "remove_from_CI" + ] + }, + "outputs": [], + "source": [ + "%pip install unified-planning\n", + "\n", + "import unified_planning as up\n", + "from unified_planning.shortcuts import *" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# A *scheduling* primer\n", + "\n", + "`unified-planning` provides initial support for modeling scheduling problems:\n", + "\n", + " - reuse state definition (`Type`,`Fluent`, initial state, (timed) goals, ...)\n", + " - replace `Action` with `Activity`\n", + " - add syntactic sugar for common patterns in scheduling problems\n", + " \n", + " \n", + " \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": true, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "problem name = factory\n", + "\n", + "fluents = [\n", + "]\n", + "\n", + "initial fluents default = [\n", + "]\n", + "\n", + "initial values = [\n", + "]\n", + "\n", + "\n", + "BASE: {\n", + " }\n", + "\n", + "Activities:\n", + " " + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from unified_planning.model.scheduling import SchedulingProblem\n", + "\n", + "# Create an empty problem called factory\n", + "problem = SchedulingProblem(\"factory\")\n", + "problem" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Resources as numeric fluents\n", + "\n", + "A `SchedulingProblem` allows boolean, symbolic and numeric fluents to state representation, just like a regular planning problem.\n", + "\n", + "In addition, it exposes an [`add_resource`](https://unified-planning.readthedocs.io/en/latest/api/model/scheduling/SchedulingProblem.html#unified_planning.model.scheduling.SchedulingProblem.add_resource) method that eases the definition of reusable resources:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "problem name = factory\n", + "\n", + "fluents = [\n", + " integer[0, 1] machine1\n", + " integer[0, 1] machine2\n", + " integer[0, 4] operators\n", + "]\n", + "\n", + "initial fluents default = [\n", + " integer[0, 1] machine1 := 1\n", + " integer[0, 1] machine2 := 1\n", + " integer[0, 4] operators := 4\n", + "]\n", + "\n", + "initial values = [\n", + "]\n", + "\n", + "\n", + "BASE: {\n", + " }\n", + "\n", + "Activities:\n", + " \n" + ] + } + ], + "source": [ + "# Create two unary resources, one for each machine\n", + "machine1 = problem.add_resource(\"machine1\", capacity=1)\n", + "machine2 = problem.add_resource(\"machine2\", capacity=1)\n", + "# Create a resource with capacity 4 representing the available operators\n", + "operators = problem.add_resource(\"operators\", capacity=4)\n", + "\n", + "print(problem)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Activities\n", + "\n", + "An [`Activity`](https://unified-planning.readthedocs.io/en/latest/api/model/scheduling/Activity.html) is essentially a **durative action** present **exactly once** in the solution." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a1 {\n", + " duration = [3, 3]\n", + " effects = [\n", + " start(a1):\n", + " machine1 -= 1:\n", + " end(a1):\n", + " machine1 += 1:\n", + " ]\n", + " }\n" + ] + } + ], + "source": [ + "# Create an activity a1 that has a duration of 3 time units that uses the machine 1\n", + "a1 = problem.add_activity(\"a1\", duration=3)\n", + "a1.uses(machine1, amount=1)\n", + "\n", + "print(a1)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a1 {\n", + " duration = [3, 3]\n", + " effects = [\n", + " start(a1):\n", + " machine1 -= 1:\n", + " operators -= 2:\n", + " end(a1):\n", + " machine1 += 1:\n", + " operators += 2:\n", + " ]\n", + " }\n" + ] + } + ], + "source": [ + "# Specify that activity a1 requires 2 operators to be executed\n", + "a1.uses(operators, amount=2)\n", + "print(a1)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "a2 {\n", + " duration = [6, 6]\n", + " constraints = [\n", + " (end(a2) <= 14)\n", + " ]\n", + " effects = [\n", + " start(a2):\n", + " operators -= 1:\n", + " machine2 -= 1:\n", + " end(a2):\n", + " operators += 1:\n", + " machine2 += 1:\n", + " ]\n", + " }" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Create a new activity a2 that lasts 6 time units and require machine2 and 1 operator\n", + "a2 = problem.add_activity(\"a2\", duration=6)\n", + "a2.uses(operators) # default usage is 1\n", + "a2.uses(machine2)\n", + "\n", + "# Require that activity be finished by time unit 14\n", + "a2.add_deadline(14)\n", + "a2" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "scrolled": true, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "problem name = factory\n", + "\n", + "fluents = [\n", + " integer[0, 1] machine1\n", + " integer[0, 1] machine2\n", + " integer[0, 4] operators\n", + "]\n", + "\n", + "initial fluents default = [\n", + " integer[0, 1] machine1 := 1\n", + " integer[0, 1] machine2 := 1\n", + " integer[0, 4] operators := 4\n", + "]\n", + "\n", + "initial values = [\n", + "]\n", + "\n", + "\n", + "BASE: {\n", + " constraints = [\n", + " (end(a2) < start(a1))\n", + " ]\n", + " effects = [\n", + " start + 17:\n", + " operators -= 1:\n", + " start + 25:\n", + " operators += 1:\n", + " ]\n", + " }\n", + "\n", + "Activities:\n", + " a1 {\n", + " duration = [3, 3]\n", + " effects = [\n", + " start(a1):\n", + " machine1 -= 1:\n", + " operators -= 2:\n", + " end(a1):\n", + " machine1 += 1:\n", + " operators += 2:\n", + " ]\n", + " }\n", + " a2 {\n", + " duration = [6, 6]\n", + " constraints = [\n", + " (end(a2) <= 14)\n", + " ]\n", + " effects = [\n", + " start(a2):\n", + " operators -= 1:\n", + " machine2 -= 1:\n", + " end(a2):\n", + " operators += 1:\n", + " machine2 += 1:\n", + " ]\n", + " }\n", + " " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# finish a2 before starting a1\n", + "problem.add_constraint(LT(a2.end, a1.start))\n", + "\n", + "# One worker is unavailable over [17, 25)\n", + "problem.add_decrease_effect(17, operators, 1)\n", + "problem.add_increase_effect(25, operators, 1)\n", + "problem" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Solving scheduling problems\n", + "\n", + "Like all problems in the UP, we can access the `kind` field that is automatically computed to reflect the features in the problem." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PROBLEM_CLASS: ['SCHEDULING']\n", + "PROBLEM_TYPE: ['SIMPLE_NUMERIC_PLANNING']\n", + "TIME: ['TIMED_EFFECTS', 'DISCRETE_TIME']\n", + "NUMBERS: ['BOUNDED_TYPES', 'DISCRETE_NUMBERS']\n", + "EFFECTS_KIND: ['DECREASE_EFFECTS', 'INCREASE_EFFECTS']\n", + "FLUENTS_TYPE: ['NUMERIC_FLUENTS']\n" + ] + } + ], + "source": [ + "print(problem.kind)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + " Currently no solver are provided in the UP that support scheduling problems natively.\n", + " \n", + " However, early support is provided in the development versions of the [aries](https://github.com/plaans/aries/tree/master/planning/unified/plugin) and [discrete-optimization](https://github.com/aiplan4eu/up-discreteoptimization) backends.\n", + "\n", + "\n", + "Reference: [Complete parser for jobshop (with operators) problems](https://github.com/aiplan4eu/unified-planning/blob/master/unified_planning/test/examples/scheduling/jobshop.py)" + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "colab": { + "collapsed_sections": [], + "name": "UP Hierarchical Planning", + "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": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" + } + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} From 18e4c31769663dc09cad955ac950f5cd06137265 Mon Sep 17 00:00:00 2001 From: Arthur Bit-Monnot Date: Wed, 11 Oct 2023 13:50:15 +0200 Subject: [PATCH 4/7] fix(doc): Move import to a cell that is not ignored in CI --- docs/notebooks/13-scheduling.ipynb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/notebooks/13-scheduling.ipynb b/docs/notebooks/13-scheduling.ipynb index 5932ce70f..ca8950320 100644 --- a/docs/notebooks/13-scheduling.ipynb +++ b/docs/notebooks/13-scheduling.ipynb @@ -36,16 +36,14 @@ "start_time": "2023-07-07T08:26:01.671820250Z" }, "id": "BoqALxJWdfl8", + "scrolled": true, "tags": [ "remove_from_CI" ] }, "outputs": [], "source": [ - "%pip install unified-planning\n", - "\n", - "import unified_planning as up\n", - "from unified_planning.shortcuts import *" + "%pip install unified-planning" ] }, { @@ -107,6 +105,7 @@ } ], "source": [ + "from unified_planning.shortcuts import *\n", "from unified_planning.model.scheduling import SchedulingProblem\n", "\n", "# Create an empty problem called factory\n", @@ -413,7 +412,7 @@ "PROBLEM_CLASS: ['SCHEDULING']\n", "PROBLEM_TYPE: ['SIMPLE_NUMERIC_PLANNING']\n", "TIME: ['TIMED_EFFECTS', 'DISCRETE_TIME']\n", - "NUMBERS: ['BOUNDED_TYPES', 'DISCRETE_NUMBERS']\n", + "NUMBERS: ['DISCRETE_NUMBERS', 'BOUNDED_TYPES']\n", "EFFECTS_KIND: ['DECREASE_EFFECTS', 'INCREASE_EFFECTS']\n", "FLUENTS_TYPE: ['NUMERIC_FLUENTS']\n" ] From 8e459a5a1bf0c7b6d244926f6096d6d53d64b4d7 Mon Sep 17 00:00:00 2001 From: Arthur Bit-Monnot Date: Wed, 11 Oct 2023 14:04:05 +0200 Subject: [PATCH 5/7] fix(doc): Move import to a cell that is not ignored in CI (hierarchical notebook) --- docs/notebooks/07-hierarchical-planning.ipynb | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/notebooks/07-hierarchical-planning.ipynb b/docs/notebooks/07-hierarchical-planning.ipynb index a75953fad..d0878a347 100644 --- a/docs/notebooks/07-hierarchical-planning.ipynb +++ b/docs/notebooks/07-hierarchical-planning.ipynb @@ -44,8 +44,24 @@ }, "outputs": [], "source": [ - "%pip install unified-planning[aries]\n", - "\n", + "%pip install unified-planning[aries]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-07T08:26:03.277967428Z", + "start_time": "2023-07-07T08:26:01.671820250Z" + }, + "id": "BoqALxJWdfl8", + "tags": [ + "remove_from_CI" + ] + }, + "outputs": [], + "source": [ "import unified_planning as up\n", "from unified_planning.shortcuts import *\n", "from unified_planning.model.htn import *" From 1c45d15a278b70e3f6eb13807858907781529cb8 Mon Sep 17 00:00:00 2001 From: Arthur Bit-Monnot Date: Thu, 12 Oct 2023 13:59:38 +0200 Subject: [PATCH 6/7] fix(doc): Fix CI tag in hierarchical notebook --- docs/notebooks/07-hierarchical-planning.ipynb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/notebooks/07-hierarchical-planning.ipynb b/docs/notebooks/07-hierarchical-planning.ipynb index d0878a347..ecb896ccb 100644 --- a/docs/notebooks/07-hierarchical-planning.ipynb +++ b/docs/notebooks/07-hierarchical-planning.ipynb @@ -49,7 +49,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2023-07-07T08:26:03.277967428Z", @@ -57,7 +57,6 @@ }, "id": "BoqALxJWdfl8", "tags": [ - "remove_from_CI" ] }, "outputs": [], @@ -99,7 +98,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2023-07-07T08:26:03.318700483Z", From 948646074faa29892052b8808ff58394c6d37d1a Mon Sep 17 00:00:00 2001 From: Arthur Bit-Monnot Date: Thu, 19 Oct 2023 13:16:30 +0200 Subject: [PATCH 7/7] doc: minor fix in notebook introductory text. --- docs/notebooks/07-hierarchical-planning.ipynb | 5 ++--- docs/notebooks/13-scheduling.ipynb | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/notebooks/07-hierarchical-planning.ipynb b/docs/notebooks/07-hierarchical-planning.ipynb index ecb896ccb..09e8a2bbf 100644 --- a/docs/notebooks/07-hierarchical-planning.ipynb +++ b/docs/notebooks/07-hierarchical-planning.ipynb @@ -26,7 +26,7 @@ "source": [ "## Setup\n", "\n", - "We start by downloading (from github) the unified planning library and a hierarchical planner (aries)." + "We start by downloading the unified planning library and a hierarchical planner (aries)." ] }, { @@ -56,8 +56,7 @@ "start_time": "2023-07-07T08:26:01.671820250Z" }, "id": "BoqALxJWdfl8", - "tags": [ - ] + "tags": [] }, "outputs": [], "source": [ diff --git a/docs/notebooks/13-scheduling.ipynb b/docs/notebooks/13-scheduling.ipynb index ca8950320..68b77b42c 100644 --- a/docs/notebooks/13-scheduling.ipynb +++ b/docs/notebooks/13-scheduling.ipynb @@ -24,7 +24,7 @@ "source": [ "## Setup\n", "\n", - "We start by downloading (from github) the unified planning library." + "We start by downloading the unified planning library." ] }, {