{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "vXUqFpLObzhb" }, "source": [ "## Optimal Planning\n", "\n", "This python notebook shows how to use the unified planning library to solve problems with a given optimality metric.\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/02-optimal-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/02-optimal-planning.ipynb)" ] }, { "cell_type": "markdown", "metadata": { "id": "t8dCcpf7mivV" }, "source": [ "### Setup\n", "\n", "We install the unified planning library." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "id": "BoqALxJWdfl8", "tags": [ "remove_from_CI" ] }, "outputs": [], "source": [ "%pip install unified-planning[fast-downward]" ] }, { "cell_type": "markdown", "metadata": { "id": "iNHFHxQKnKIp" }, "source": [ "We are now ready to use the Unified-Planning library!" ] }, { "cell_type": "markdown", "metadata": { "id": "xI2BGgmvdsek" }, "source": [ "### Problem Definition\n" ] }, { "cell_type": "markdown", "metadata": { "id": "bu91rHtQ34Wh" }, "source": [ "In this demo we show how to model a problem with an optimality metric and how to solve it following the given metric." ] }, { "cell_type": "markdown", "metadata": { "id": "xn5l-SVxufFA" }, "source": [ "We start importing the shortcuts." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "id": "otZVSku3idJC" }, "outputs": [], "source": [ "from unified_planning.shortcuts import *\n", "from unified_planning.engines import PlanGenerationResultStatus" ] }, { "cell_type": "markdown", "metadata": { "id": "M9DCTuoSu2vh" }, "source": [ "Now we start to model a basic problem with action costs." ] }, { "cell_type": "markdown", "metadata": { "id": "5iISKqwryXFT" }, "source": [ "\n", "\n", "In the following code we will create a simple problem that can be solved in 2 different ways depending on the given optimality metric." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "id": "e5BWi6wyuqyB" }, "outputs": [], "source": [ "# basic with actions cost\n", "x = Fluent(\"x\")\n", "y = Fluent(\"y\")\n", "\n", "a = InstantaneousAction(\"a\")\n", "a.add_precondition(Not(x))\n", "a.add_effect(x, True)\n", "\n", "b = InstantaneousAction(\"b\")\n", "b.add_precondition(Not(y))\n", "b.add_effect(y, True)\n", "\n", "c = InstantaneousAction(\"c\")\n", "c.add_precondition(y)\n", "c.add_effect(x, True)\n", "\n", "problem = Problem(\"simple_with_costs\")\n", "\n", "problem.add_fluent(x)\n", "problem.add_fluent(y)\n", "\n", "problem.add_action(a)\n", "problem.add_action(b)\n", "problem.add_action(c)\n", "\n", "problem.set_initial_value(x, False)\n", "problem.set_initial_value(y, False)\n", "\n", "problem.add_goal(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Quality Metric\n", "\n", "Now, we add to the problem the quality metric that we want the planner to use.\n", "\n", "In this case, we will use the metric that minimizes the total action costs of the plan." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "problem.add_quality_metric(\n", " up.model.metrics.MinimizeActionCosts({a: 10, b: 1, c: 1})\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Getting the optimal plan\n", "\n", "As we can see, the action `a` would satisfy the goal in just one action, but the plan would have cost `10`. \n", "Instead, if we do `b` then `c`, we also satisfy the goal, but the plan total cost would be `2`." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "expected_plan = up.plans.SequentialPlan(\n", " [up.plans.ActionInstance(b), up.plans.ActionInstance(c)]\n", ")" ] }, { "cell_type": "markdown", "metadata": { "id": "aMMtRDVovvuM" }, "source": [ "Then, we get a solver that guarantees that the problem can be solved optimally." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "id": "vEDxcqkLvm9d" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[96m *** Credits ***\n", "\u001b[0m\u001b[96m * In operation mode `OneshotPlanner` at line 1 of `/tmp/ipykernel_152691/2144990037.py`, \u001b[0m\u001b[96myou are using the following planning engine:\n", "\u001b[0m\u001b[96m * Engine name: Fast Downward\n", " * Developers: Uni Basel team and contributors (cf. https://github.com/aibasel/downward/blob/main/README.md)\n", "\u001b[0m\u001b[96m * Description: \u001b[0m\u001b[96mFast Downward is a domain-independent classical planning system.\u001b[0m\u001b[96m\n", "\u001b[0m\u001b[96m\n", "\u001b[0m" ] } ], "source": [ "with OneshotPlanner(\n", " problem_kind=problem.kind,\n", " optimality_guarantee=PlanGenerationResultStatus.SOLVED_OPTIMALLY,\n", ") as planner:\n", " final_report = planner.solve(problem)\n", " plan = final_report.plan" ] }, { "cell_type": "markdown", "metadata": { "id": "SIA9pRCiwEql" }, "source": [ "Here, we assume that the plan is the one we expected, and not the shortest one, and that it is `SOLVED_OPTIMALLY`." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "id": "b1Xnzzq7wOxw" }, "outputs": [], "source": [ "assert final_report.status == PlanGenerationResultStatus.SOLVED_OPTIMALLY\n", "assert plan == expected_plan" ] }, { "cell_type": "markdown", "metadata": { "id": "vidUnHLh3gOz" }, "source": [ "### Change quality metric and get different optimal plan\n", "\n", "We change the problem quality metrics by removing all the current metrics and add a new one; we will ask for the shortest possible plan." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "id": "xl8dm2fZ3gpp" }, "outputs": [], "source": [ "problem.clear_quality_metrics()\n", "problem.add_quality_metric(up.model.metrics.MinimizeSequentialPlanLength())" ] }, { "cell_type": "markdown", "metadata": { "id": "mjdfaQw537eI" }, "source": [ "We get a planner from the factory that is capable of handling the new type of optimality requirement." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "id": "8NFqgnnlyeAc" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[96m *** Credits ***\n", "\u001b[0m\u001b[96m * In operation mode `OneshotPlanner` at line 1 of `/tmp/ipykernel_152691/2144990037.py`, \u001b[0m\u001b[96myou are using the following planning engine:\n", "\u001b[0m\u001b[96m * Engine name: Fast Downward\n", " * Developers: Uni Basel team and contributors (cf. https://github.com/aibasel/downward/blob/main/README.md)\n", "\u001b[0m\u001b[96m * Description: \u001b[0m\u001b[96mFast Downward is a domain-independent classical planning system.\u001b[0m\u001b[96m\n", "\u001b[0m\u001b[96m\n", "\u001b[0m" ] } ], "source": [ "with OneshotPlanner(\n", " problem_kind=problem.kind,\n", " optimality_guarantee=PlanGenerationResultStatus.SOLVED_OPTIMALLY,\n", ") as planner:\n", " final_report = planner.solve(problem)\n", " plan = final_report.plan" ] }, { "cell_type": "markdown", "metadata": { "id": "kLDlxvwL39dh" }, "source": [ "Then, we define the shortest plan possible (only the action `a`) and we assume that the result is `SOLVED_OPTIMALLY`." ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "id": "S4rT6f0A3qRJ" }, "outputs": [], "source": [ "expected_plan = up.plans.SequentialPlan(\n", " [up.plans.ActionInstance(a)]\n", ")\n", "assert final_report.status == PlanGenerationResultStatus.SOLVED_OPTIMALLY\n", "assert plan == expected_plan" ] } ], "metadata": { "celltoolbar": "Tags", "colab": { "collapsed_sections": [], "name": "Optimal 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.6" }, "vscode": { "interpreter": { "hash": "0f093686f7df634549cfcc38b496d64db351fb20473bb5b931eecb8ae35c8804" } } }, "nbformat": 4, "nbformat_minor": 1 }