{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "QiGealjaVJNw" }, "source": [ "# Multi-Agent Plan Simple Example\n", "\n", "This python notebook shows how to use the unified planning library to model multi-agent problems.\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/09-multiagent-planning-simple.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/09-multiagent-planning-simple.ipynb)" ] }, { "cell_type": "markdown", "metadata": { "id": "JvKlg7cm8tBo" }, "source": [ "## Setup\n", "\n", "We start by installing the unified planning library and a multi-agent planner (FMAP)." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "aIxg95xz5EMo", "outputId": "44a3c006-f512-4f4e-9051-fab23c83970d", "tags": [ "remove_from_CI" ] }, "outputs": [], "source": [ "!pip install unified-planning[fmap]" ] }, { "cell_type": "markdown", "metadata": { "id": "OY-4EFALUj00" }, "source": [ "We are now ready to use the Unified-Planning library!" ] }, { "cell_type": "markdown", "metadata": { "id": "Vh5X0ZqRVVEA" }, "source": [ "## Demo\n" ] }, { "cell_type": "markdown", "metadata": { "id": "LY7O_siBU0V9" }, "source": [ "In this demo we show how to model a multi-agent planning problem using the Unified Planning library." ] }, { "cell_type": "markdown", "metadata": { "id": "tiQrjJOsV5zM" }, "source": [ "### Basic imports" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "id": "dF8NSQydRRBO" }, "outputs": [], "source": [ "from unified_planning.shortcuts import *\n", "from unified_planning.model.multi_agent import *\n", "from collections import namedtuple\n", "from unified_planning.io.ma_pddl_writer import MAPDDLWriter" ] }, { "cell_type": "markdown", "metadata": { "id": "lUvelsbfWE9f" }, "source": [ "### Creating the simple-MA problem" ] }, { "cell_type": "markdown", "metadata": { "id": "WK2NwCw7XPB0" }, "source": [ "The class that represents a multi-agent planning problem is unified_planning.MultiAgentProblem, it contains the set of agents, the objects, an intial value for all the fluents and a goal to be reached by the planner.\n", "We create a `MultiAgentProblem` and two `Agents`. An `Agent` is an individual entity with specific fluents and specific\n", "actions." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "id": "xtPm63jkRRIE" }, "outputs": [], "source": [ "problem = MultiAgentProblem(\"simple_MA\")\n", "\n", "#AGENTs\n", "robot_a = Agent(\"robot_a\", problem)\n", "scale_a = Agent(\"scale_a\", problem)" ] }, { "cell_type": "markdown", "metadata": { "id": "_4P9_BnPeXA-" }, "source": [ "We define the UserTypes, the Objects, the Fluents and the Actions" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "id": "66JwC79NRRMz" }, "outputs": [], "source": [ "#USERTYPEs\n", "Location = UserType(\"Location\")\n", "door = UserType(\"door\")\n", "\n", "#FLUENTs\n", "open = Fluent(\"open\", door=door)\n", "pos = Fluent(\"pos\", loc=Location)\n", "\n", "#OBJECTs\n", "home = Object(\"home\", Location)\n", "office = Object(\"office\", Location)\n", "open20 = Object(\"open20\", door)\n", "close20 = Object(\"close20\", door)\n", "\n", "#ACTIONs\n", "movegripper = InstantaneousAction(\"movegripper\")\n", "movegripper.add_precondition(pos(office))\n", "movegripper.add_effect(pos(home), True)\n", "\n", "open_door = InstantaneousAction(\"open_door\")\n", "open_door.add_precondition(open(close20))\n", "open_door.add_effect(open(open20), True)" ] }, { "cell_type": "markdown", "metadata": { "id": "NIejvKXAetMK" }, "source": [ "Let's add the `Fluents` to the `Agents`. Note: An agent's fluent can be of two types, public or private. `Public Fluents` are visible to other agents. In contrast, the `Private Fluents` are not visible from the other agents.\n", "Private fluents are added to the agent via the `add_fluent` or `add_private_fluent` methods and public fluents via the `add_public_fluent` method." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "LhlkeJ-ge2of", "outputId": "21cceb3b-a180-49cf-dff0-3a5a1e339a96" }, "outputs": [ { "data": { "text/plain": [ "bool open[door=door]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "robot_a.add_fluent(pos, default_initial_value=False)\n", "scale_a.add_fluent(open, default_initial_value=False)" ] }, { "cell_type": "markdown", "metadata": { "id": "4uhPijdDivoR" }, "source": [ "We add to the agents the actions they can perform." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "id": "4pCaQ6cQRRQc" }, "outputs": [], "source": [ "robot_a.add_action(movegripper)\n", "scale_a.add_action(open_door)" ] }, { "cell_type": "markdown", "metadata": { "id": "WOFJtvHnjC_I" }, "source": [ "Let's add the agents to the `MultiAgentProblem`." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "id": "ZK0kyCHUjCVi" }, "outputs": [], "source": [ "problem.add_agent(robot_a)\n", "problem.add_agent(scale_a)" ] }, { "cell_type": "markdown", "metadata": { "id": "Pl78ABIni9FV" }, "source": [ "We add the objects, the initial values and the goals. \n", "Note: `Dot` operator is used to denote agent-specific `Fluents`." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "id": "tXu5TET8RRWx" }, "outputs": [], "source": [ "#OBJECTs\n", "problem.add_object(home)\n", "problem.add_object(office)\n", "problem.add_object(open20)\n", "problem.add_object(close20)\n", "\n", "#INITIAL VALUEs\n", "problem.set_initial_value(Dot(robot_a, pos(office)), True)\n", "problem.set_initial_value(Dot(scale_a, open(close20)), True)\n", "\n", "#GOALs\n", "problem.add_goal(Dot(robot_a, pos(home)))\n", "problem.add_goal(Dot(scale_a, open(open20)))" ] }, { "cell_type": "markdown", "metadata": { "id": "-mJ_Lrl6nTcQ" }, "source": [ "### MA-PDDL Writer" ] }, { "cell_type": "markdown", "metadata": { "id": "KEkzMePBpB3x" }, "source": [ "To write the ma-pddl equivalent of a `unified_planning MultiAgentProblem` to a file we use the `MAPDDLWriter.write_ma_domain` and `MAPDDLWriter.write_ma_problem` methods." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "id": "zI9eG8iWRvUe" }, "outputs": [], "source": [ "w = MAPDDLWriter(problem)\n", "w.write_ma_domain(\"simple_ma\")\n", "w.write_ma_problem(\"simple_ma\")" ] }, { "cell_type": "markdown", "metadata": { "id": "UxrMTuOqVmzJ" }, "source": [ "## Solving Multi-Agent Planning Problems" ] }, { "cell_type": "markdown", "metadata": { "id": "9SRCqarrVo6H" }, "source": [ "We can use fmap to solve a Multi-Agent problem.\n", "It allows the specification of a specific heuristic function used to evaluate the quality of the plans. The name of the custom parameter is heuristic and the following values are supported:\n", "\n", " - 0 - FF heuristic: guides the search through the well-known h_FF heuristic function. This option is available for single-agent planning tasks only.\n", " - 1 - DTG heuristic: evaluates plans via the heuristic h_DTG.\n", " - 2 - default option - DTG + Landmarks: this option applies the multi-heuristic search scheme of the MH-FMAP solver by combining the h_DTG and h_Land heuristics to guide the search.\n", " - 3 - Inc. DTG + Landmarks: incremental multi-heuristic mode that makes use of h_DTG and h_Land." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "4OF98T8i5ZOl", "outputId": "e812e0be-6c56-4903-f2ab-e4ddf331f289" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[96m\u001b[1mNOTE: To disable printing of planning engine credits, add this line to your code: `up.shortcuts.get_environment().credits_stream = None`\n", "\u001b[0m\u001b[96m *** Credits ***\n", "\u001b[0m\u001b[96m * In operation mode `OneshotPlanner` at line 1 of `/tmp/ipykernel_157727/678844819.py`, \u001b[0m\u001b[96myou are using the following planning engine:\n", "\u001b[0m\u001b[96m * Engine name: FMAP\n", " * Developers: Alejandro TorreƱo, Oscar Sapena and Eva Onaindia\n", "\u001b[0m\u001b[96m * Description: \u001b[0m\u001b[96mFMAP: A Platform for the Development of Distributed Multi-Agent Planning Systems.\u001b[0m\u001b[96m\n", "\u001b[0m\u001b[96m\n", "\u001b[0mFMAP Returned Sequential Plans object: \n", "0 Sequential Plans: SequentialPlan:\n", " scale_a.open_door\n", " robot_a.movegripper\n", "1 Sequential Plans: SequentialPlan:\n", " robot_a.movegripper\n", " scale_a.open_door\n", "Adjacency list: {robot_a.movegripper: [], scale_a.open_door: []}\n", "result: status: SOLVED_SATISFICING\n", "engine: FMAP\n", "plan: PartialOrderPlan:\n", " actions:\n", " 0) robot_a.movegripper\n", " 1) scale_a.open_door\n", " constraints:\n" ] } ], "source": [ "with OneshotPlanner(name='fmap', params={'heuristic': '1'}) as planner:\n", " result = planner.solve(problem)\n", " if result.status == up.engines.PlanGenerationResultStatus.SOLVED_SATISFICING:\n", " print(\"%s Returned Sequential Plans object: %s\" % (planner.name, result.plan.all_sequential_plans()))\n", " [print(f\"{idx} Sequential Plans: {seq_plan}\") for idx, seq_plan in enumerate(result.plan.all_sequential_plans())]\n", " print(\"Adjacency list:\", result.plan.get_adjacency_list)\n", " print(\"result:\", result)\n", " else:\n", " print(\"Log Error:\", result)" ] } ], "metadata": { "celltoolbar": "Tags", "colab": { "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" } }, "nbformat": 4, "nbformat_minor": 1 }