diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..60086b0216a388ad03ba67360dac9e8dabe6e33c --- /dev/null +++ b/.gitignore @@ -0,0 +1,146 @@ + +# Created by https://www.gitignore.io/api/linux,python,jupyternotebooks,visualstudiocode +# Edit at https://www.gitignore.io/?templates=linux,python,jupyternotebooks,visualstudiocode + +### JupyterNotebooks ### +# gitignore template for Jupyter Notebooks +# website: http://jupyter.org/ + +.ipynb_checkpoints +*/.ipynb_checkpoints/* + +# IPython +profile_default/ +ipython_config.py + +# Remove previous ipynb_checkpoints +# git rm -r .ipynb_checkpoints/ + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +### VisualStudioCode ### +.vscode + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +# End of https://www.gitignore.io/api/linux,python,jupyternotebooks,visualstudiocode diff --git a/AP-Jupyternotebook.ipynb b/AP-Jupyternotebook.ipynb index a73d63c08727f03b4f361883d5a09c501c684b5e..f73a02a7a3af22c3168801fba842140caeb1ed1f 100644 --- a/AP-Jupyternotebook.ipynb +++ b/AP-Jupyternotebook.ipynb @@ -123,14 +123,20 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2020-05-14T12:14:24.358009Z", + "start_time": "2020-05-14T12:14:24.354268Z" + } + }, "outputs": [], "source": [ "def applicable(state, precondition):\n", - " positive, negative = precondition \n", + " positive, negative = precondition\n", " return positive.issubset(state) and not negative.intersection(state)\n", "\n", + "\n", "def apply(state, effects):\n", " positive, negative = effects\n", " return frozenset(state.difference(negative).union(positive))" @@ -145,9 +151,44 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2020-05-14T12:14:29.575958Z", + "start_time": "2020-05-14T12:14:29.561574Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "move\n", + "['r1', 'l1', 'l2']\n", + "frozenset({('at', 'r1', 'l1'), ('adjacent', 'l1', 'l2')})\n", + "frozenset({('occupied', 'l2')})\n", + "frozenset({('occupied', 'l2'), ('at', 'r1', 'l2')})\n", + "frozenset({('occupied', 'l1'), ('at', 'r1', 'l1')})\n", + "---------------------------------------------\n", + "Is the action move applicable? True\n", + "---------------------------------------------\n", + "Resulting state:\n", + "('empty', 'k2')\n", + "('empty', 'k1')\n", + "('attached', 'p1', 'l1')\n", + "('at', 'r1', 'l2')\n", + "('attached', 'q2', 'l2')\n", + "('adjacent', 'l1', 'l2')\n", + "('belong', 'k1', 'l1')\n", + "('adjacent', 'l2', 'l1')\n", + "('on', 'ca', 'pallet')\n", + "('occupied', 'l2')\n", + "---------------------------------------------\n", + "Was the goal achieved? False\n", + "---------------------------------------------\n" + ] + } + ], "source": [ "from pddl.action import Action\n", "\n", @@ -155,11 +196,12 @@ "\n", "# An action to move robot r1 from location l1 to location l2\n", "a1 = Action(\n", - " 'move', #Action name\n", - " ['r1', 'l1', 'l2'], #Parameters\n", - " frozenset({('at', 'r1', 'l1'), ('adjacent', 'l1', 'l2')}), #Positive preconditions\n", - " frozenset({('occupied', 'l2')}), #Negative preconditions\n", - " frozenset({('at', 'r1', 'l2'), ('occupied', 'l2')}), #Add effects\n", + " 'move', #Action name\n", + " ['r1', 'l1', 'l2'], #Parameters\n", + " frozenset({('at', 'r1', 'l1'),\n", + " ('adjacent', 'l1', 'l2')}), #Positive preconditions\n", + " frozenset({('occupied', 'l2')}), #Negative preconditions\n", + " frozenset({('at', 'r1', 'l2'), ('occupied', 'l2')}), #Add effects\n", " frozenset({('at', 'r1', 'l1'), ('occupied', 'l1')}) #Del effects\n", ")\n", "\n", @@ -184,9 +226,12 @@ " ('on', 'ca', 'pallet'),\n", " ('at', 'r1', 'l1'),\n", " ('belong', 'k1', 'l1'),\n", - " ('adjacent', 'l1', 'l2'), ('adjacent', 'l2', 'l1'), ('attached', 'q2', 'l2'),\n", + " ('adjacent', 'l1', 'l2'),\n", + " ('adjacent', 'l2', 'l1'),\n", + " ('attached', 'q2', 'l2'),\n", " ('empty', 'k2'),\n", - " ('attached', 'p1', 'l1'), ('occupied', 'l1'),\n", + " ('attached', 'p1', 'l1'),\n", + " ('occupied', 'l1'),\n", " ('empty', 'k1'),\n", " # ...\n", "})\n", @@ -196,7 +241,8 @@ "negative_goal = frozenset()\n", "\n", "#Test if the action move (variable a1) is applicable in our initial state (initial_state)\n", - "applicable_action = applicable(initial_state, (a1.positive_preconditions, a1.negative_preconditions))\n", + "applicable_action = applicable(\n", + " initial_state, (a1.positive_preconditions, a1.negative_preconditions))\n", "print('Is the action move applicable?', applicable_action)\n", "\n", "print('---------------------------------------------')\n", @@ -209,7 +255,7 @@ "\n", "print('---------------------------------------------')\n", "\n", - "#Test if the goal was achieved \n", + "#Test if the goal was achieved\n", "goal_achieved = applicable(resulting_state, (positive_goal, negative_goal))\n", "print('Was the goal achieved?', goal_achieved)\n", "\n", @@ -220,7 +266,7 @@ "plan = []\n", "# Preconditions and effects are empty when obtained from a plan file, may be filled when obtained from the planner\n", "plan = [\n", - " Action('take', ['k1', 'cc', 'cb', 'p1', 'l1'], [], [], [], []), \n", + " Action('take', ['k1', 'cc', 'cb', 'p1', 'l1'], [], [], [], []),\n", " Action('load', ['k1', 'r1', 'cc', 'l1'], [], [], [], []),\n", " Action('move', ['r1', 'l1', 'l2'], [], [], [], []),\n", " Action('unload', ['k2', 'r1', 'cc', 'l2'], [], [], [], [])\n", @@ -230,7 +276,7 @@ "plan = None\n", "\n", "# A valid plan is either true or false\n", - "valid_plan = True\n", + "valid_plan = True\n", "invalid_plan = False" ] }, @@ -300,8 +346,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { + "ExecuteTime": { + "end_time": "2020-05-14T12:15:56.491481Z", + "start_time": "2020-05-14T12:15:55.410617Z" + }, "deletable": false, "nbgrader": { "cell_type": "code", @@ -362,8 +412,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { + "ExecuteTime": { + "end_time": "2020-05-14T12:15:58.935982Z", + "start_time": "2020-05-14T12:15:58.929161Z" + }, "deletable": false, "nbgrader": { "cell_type": "code", @@ -417,8 +471,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": { + "ExecuteTime": { + "end_time": "2020-05-14T12:16:01.667588Z", + "start_time": "2020-05-14T12:16:01.626551Z" + }, "deletable": false, "nbgrader": { "cell_type": "code", @@ -510,8 +568,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": { + "ExecuteTime": { + "end_time": "2020-05-14T12:16:05.396647Z", + "start_time": "2020-05-14T12:16:05.315892Z" + }, "deletable": false, "editable": false, "nbgrader": { @@ -525,7 +587,21 @@ "solution": false } }, - "outputs": [], + "outputs": [ + { + "ename": "NotImplementedError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNotImplementedError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 40\u001b[0m \u001b[0;31m# Apply Hmax to initial states of many problems from many domains\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 41\u001b[0m \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mMaxHeuristic\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 42\u001b[0;31m \u001b[0mtest_heuristic\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdwr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpb1_dwr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 43\u001b[0m \u001b[0mtest_heuristic\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdwr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpb2_dwr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 44\u001b[0m \u001b[0mtest_heuristic\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtsp\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpb1_tsp\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mtest_heuristic\u001b[0;34m(domain, problem, h, expected)\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mtest_heuristic\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdomain\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mexpected\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0mparser\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mactions\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparse_domain_problem\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdomain\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 37\u001b[0;31m \u001b[0mv\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mactions\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparser\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstate\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mparser\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpositive_goals\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparser\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnegative_goals\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 38\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Expected \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexpected\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m\", got:\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m'. Correct!'\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mv\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mexpected\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0;34m'. False!'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mh\u001b[0;34m(self, actions, state, goals)\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mactions\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstate\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mgoals\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;31m# YOUR CODE HERE\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mNotImplementedError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 8\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mfloat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"inf\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNotImplementedError\u001b[0m: " + ] + } + ], "source": [ "from pddl.pddl_parser import PDDLParser\n", "from pddl.action import Action\n", @@ -600,8 +676,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { + "ExecuteTime": { + "end_time": "2020-05-14T12:17:41.254107Z", + "start_time": "2020-05-14T12:17:41.166491Z" + }, "deletable": false, "editable": false, "nbgrader": { @@ -636,8 +716,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": { + "ExecuteTime": { + "end_time": "2020-05-14T12:17:44.153444Z", + "start_time": "2020-05-14T12:17:44.147001Z" + }, "deletable": false, "editable": false, "nbgrader": { @@ -1147,8 +1231,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": { + "ExecuteTime": { + "end_time": "2020-05-14T12:17:54.469983Z", + "start_time": "2020-05-14T12:17:54.444659Z" + }, "deletable": false, "nbgrader": { "cell_type": "code", @@ -1161,7 +1249,20 @@ "task": false } }, - "outputs": [], + "outputs": [ + { + "ename": "NotImplementedError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNotImplementedError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0;32mclass\u001b[0m \u001b[0mCriticalPathHeuristic\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mHeuristic\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 12\u001b[0m \u001b[0;34m\"\"\"Haslum's H^m Heuristic\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mCriticalPathHeuristic\u001b[0;34m()\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0;31m# You can put any additional methods here, please erase the \"raise NotImplementedError()\" line below\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;31m# YOUR CODE HERE\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 32\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mNotImplementedError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 33\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 34\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mactions\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minitial_state\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mgoal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNotImplementedError\u001b[0m: " + ] + } + ], "source": [ "class DeleteRelaxationHeuristic(Heuristic):\n", " \"\"\"Optimal Delete Relaxation Heuristic. \n", @@ -1263,8 +1364,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": { + "ExecuteTime": { + "end_time": "2020-05-14T12:17:59.034547Z", + "start_time": "2020-05-14T12:17:59.020092Z" + }, "deletable": false, "nbgrader": { "cell_type": "code", @@ -1343,8 +1448,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { + "ExecuteTime": { + "end_time": "2020-05-14T12:18:02.049797Z", + "start_time": "2020-05-14T12:18:01.995125Z" + }, "deletable": false, "editable": false, "nbgrader": { @@ -1358,7 +1467,22 @@ "solution": false } }, - "outputs": [], + "outputs": [ + { + "ename": "NotImplementedError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNotImplementedError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mplan_empty\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"examples/dwr/empty.plan\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0mval\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mValidator\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Expected True, got:\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mval\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate_file\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdwr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpb1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mplan1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 8\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Expected True, got:\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mval\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate_file\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdwr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpb1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mplan2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Expected False, got:\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mval\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate_file\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdwr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpb1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mplan_empty\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mvalidate_file\u001b[0;34m(self, domainfile, problemfile, planfile)\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mvalidate_file\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdomainfile\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mproblemfile\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mplanfile\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate_plan\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdomainfile\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mproblemfile\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparse_plan\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mplanfile\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 16\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mvalidate_plan\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdomainfile\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mproblemfile\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mplan\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mvalidate_plan\u001b[0;34m(self, domainfile, problemfile, plan)\u001b[0m\n\u001b[1;32m 25\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mact\u001b[0m \u001b[0;32min\u001b[0m \u001b[0maction\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgroundify\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mparser\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mobjects\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 26\u001b[0m \u001b[0mground_actions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mact\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 27\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mground_actions\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparser\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstate\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mparser\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpositive_goals\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparser\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnegative_goals\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mplan\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 28\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[0;31m# =====================================\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mvalidate\u001b[0;34m(self, actions, initial_state, goals, plan)\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mvalidate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mactions\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minitial_state\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mgoals\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mplan\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;31m# YOUR CODE HERE\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 40\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mNotImplementedError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 41\u001b[0m \u001b[0;32mpass\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNotImplementedError\u001b[0m: " + ] + } + ], "source": [ "dwr = \"examples/dwr/dwr.pddl\"\n", "pb1 = \"examples/dwr/pb1.pddl\"\n", @@ -2016,9 +2140,9 @@ ], "metadata": { "kernelspec": { - "display_name": "py36_heu", + "display_name": "Python 3", "language": "python", - "name": "py36_heu" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -2030,7 +2154,20 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.8.2" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": true } }, "nbformat": 4, diff --git a/pddl/action.py b/pddl/action.py index 5827f81e80ce6f31dda530a10b9d060c29f5ce94..c6db26b92c43a3abbc66007a6d46fc8baacf0a3f 100644 --- a/pddl/action.py +++ b/pddl/action.py @@ -5,8 +5,15 @@ import itertools class Action: - - def __init__(self, name, parameters, positive_preconditions, negative_preconditions, add_effects, del_effects): + def __init__( + self, + name, + parameters, + positive_preconditions, + negative_preconditions, + add_effects, + del_effects, + ): self.name = name self.parameters = parameters self.positive_preconditions = positive_preconditions @@ -15,27 +22,38 @@ class Action: self.del_effects = del_effects def __repr__(self): - if len(self.parameters) > 0: # Empty lists gave us grief before + if len(self.parameters) > 0: # Empty lists gave us grief before return "({!s} {!r})".format(self.name, *list(self.parameters)) else: return "({!s})".format(self.name) def __str__(self): - return 'action: ' + self.name + \ - '\n parameters: ' + str(self.parameters) + \ - '\n positive_preconditions: ' + str(list(self.positive_preconditions)) + \ - '\n negative_preconditions: ' + str(list(self.negative_preconditions)) + \ - '\n add_effects: ' + str(list(self.add_effects)) + \ - '\n del_effects: ' + str(list(self.del_effects)) + '\n' + return ( + "action: " + + self.name + + "\n parameters: " + + str(self.parameters) + + "\n positive_preconditions: " + + str(list(self.positive_preconditions)) + + "\n negative_preconditions: " + + str(list(self.negative_preconditions)) + + "\n add_effects: " + + str(list(self.add_effects)) + + "\n del_effects: " + + str(list(self.del_effects)) + + "\n" + ) def __eq__(self, other): return self.__dict__ == other.__dict__ - + def __hash__(self): - return hash((self.name, self.parameters)) # This should work even in the ground case. + return hash( + (self.name, self.parameters) + ) # This should work even in the ground case. def signature(self): - return tuple([self.name]+list(self.parameters)) + return tuple([self.name] + list(self.parameters)) def groundify(self, objects): if not self.parameters: @@ -47,20 +65,39 @@ class Action: type_map.append(objects[type]) variables.append(var) for assignment in itertools.product(*type_map): - positive_preconditions = self.replace(self.positive_preconditions, variables, assignment) - negative_preconditions = self.replace(self.negative_preconditions, variables, assignment) + positive_preconditions = self.replace( + self.positive_preconditions, variables, assignment + ) + negative_preconditions = self.replace( + self.negative_preconditions, variables, assignment + ) add_effects = self.replace(self.add_effects, variables, assignment) del_effects = self.replace(self.del_effects, variables, assignment) - yield Action(self.name, assignment, positive_preconditions, negative_preconditions, add_effects, del_effects) + yield Action( + self.name, + assignment, + positive_preconditions, + negative_preconditions, + add_effects, + del_effects, + ) def is_mutex(self, an_action): - if self.positive_preconditions.intersection(an_action.negative_preconditions | an_action.del_effects): + if self.positive_preconditions.intersection( + an_action.negative_preconditions | an_action.del_effects + ): return True - if self.negative_preconditions.intersection(an_action.positive_preconditions | an_action.add_effects): + if self.negative_preconditions.intersection( + an_action.positive_preconditions | an_action.add_effects + ): return True - if self.add_effects.intersection(an_action.negative_preconditions | an_action.del_effects): + if self.add_effects.intersection( + an_action.negative_preconditions | an_action.del_effects + ): return True - if self.del_effects.intersection(an_action.positive_preconditions | an_action.add_effects): + if self.del_effects.intersection( + an_action.positive_preconditions | an_action.add_effects + ): return True def replace(self, group, variables, assignment): @@ -71,24 +108,23 @@ class Action: for v in variables: while v in a: i = a.index(v) - a = a[:i] + tuple([assignment[iv]]) + a[i+1:] + a = a[:i] + tuple([assignment[iv]]) + a[i + 1 :] iv += 1 g.append(a) return frozenset(g) -if __name__ == '__main__': - a = Action('move', [['?ag', 'agent'], ['?from', 'pos'], ['?to', 'pos']], - frozenset([tuple(['at', '?ag', '?from']), tuple(['adjacent', '?from', '?to'])]), - frozenset([tuple(['at', '?ag', '?to'])]), - frozenset([tuple(['at', '?ag', '?to'])]), - frozenset([tuple(['at', '?ag', '?from'])]) - ) +if __name__ == "__main__": + a = Action( + "move", + [["?ag", "agent"], ["?from", "pos"], ["?to", "pos"]], + frozenset([tuple(["at", "?ag", "?from"]), tuple(["adjacent", "?from", "?to"])]), + frozenset([tuple(["at", "?ag", "?to"])]), + frozenset([tuple(["at", "?ag", "?to"])]), + frozenset([tuple(["at", "?ag", "?from"])]), + ) print(a) - objects = { - 'agent': ['ana', 'bob'], - 'pos': ['p1', 'p2'] - } + objects = {"agent": ["ana", "bob"], "pos": ["p1", "p2"]} for act in a.groundify(objects): print(act) diff --git a/pddl/benchmark.py b/pddl/benchmark.py index 37a3bb39d096061d7802de75192a43356ed42c4e..417c119f7a0fbb8b070217f17c42969e4d71956a 100644 --- a/pddl/benchmark.py +++ b/pddl/benchmark.py @@ -1,5 +1,6 @@ import matplotlib.pyplot as plt + class Singleton(type): _instances = {} @@ -10,7 +11,6 @@ class Singleton(type): class InstanceStats: - def __init__(self, domain_name="problem.pddl", problem_name="pb.pddl"): self.domain_name = domain_name self.problem_name = problem_name @@ -20,14 +20,20 @@ class InstanceStats: self.time = 0 def __str__(self): - return '%s, %s, %d, %d, %d, %f s'%(self.domain_name,self.problem_name, self.nodes, self.h_calls, self.action_space, self.time) + return "%s, %s, %d, %d, %d, %f s" % ( + self.domain_name, + self.problem_name, + self.nodes, + self.h_calls, + self.action_space, + self.time, + ) def __repr__(self): return str(self) class PlanningBenchmark(metaclass=Singleton): - def __init__(self): self.stat_instances = {} @@ -43,43 +49,74 @@ class PlanningBenchmark(metaclass=Singleton): domain[problem_name] = InstanceStats(domain_name, problem_name) return domain[problem_name] - def get_stats(self, domain_name, stat='time', xaxis='action', approach=None): - if stat == 'time': - y = [instance.time for k, instance in self.stat_instances[domain_name].items()] - elif stat == 'nodes': - y = [instance.nodes for k, instance in self.stat_instances[domain_name].items()] - elif stat == 'h_calls': - y = [instance.h_calls for k, instance in self.stat_instances[domain_name].items()] - - if xaxis == 'action': - x = [instance.action_space for k, instance in self.stat_instances[domain_name].items()] - elif xaxis == 'problem': - x = [instance.problem_name[instance.problem_name.rfind('/')+1:] for k, instance in self.stat_instances[domain_name].items()] - - return x,y - - def plot_stat(self, domain_name, stat='time', xaxis='action', label='', approach=None): - if label == '': - label = '%s: %s by %s (%s)'%(xaxis,stat,domain_name,approach) - - if stat == 'time': - y = [instance.time for k, instance in self.stat_instances[domain_name].items()] - elif stat == 'nodes': - y = [instance.node for k, instance in self.stat_instances[domain_name].items()] - elif stat == 'h_calls': - y = [instance.problem_name[instance.problem_name.rfind('/')+1:] for k, instance in self.stat_instances[domain_name].items()] + def get_stats(self, domain_name, stat="time", xaxis="action", approach=None): + if stat == "time": + y = [ + instance.time + for k, instance in self.stat_instances[domain_name].items() + ] + elif stat == "nodes": + y = [ + instance.nodes + for k, instance in self.stat_instances[domain_name].items() + ] + elif stat == "h_calls": + y = [ + instance.h_calls + for k, instance in self.stat_instances[domain_name].items() + ] + + if xaxis == "action": + x = [ + instance.action_space + for k, instance in self.stat_instances[domain_name].items() + ] + elif xaxis == "problem": + x = [ + instance.problem_name[instance.problem_name.rfind("/") + 1 :] + for k, instance in self.stat_instances[domain_name].items() + ] + + return x, y + + def plot_stat( + self, domain_name, stat="time", xaxis="action", label="", approach=None + ): + if label == "": + label = "%s: %s by %s (%s)" % (xaxis, stat, domain_name, approach) + + if stat == "time": + y = [ + instance.time + for k, instance in self.stat_instances[domain_name].items() + ] + elif stat == "nodes": + y = [ + instance.node + for k, instance in self.stat_instances[domain_name].items() + ] + elif stat == "h_calls": + y = [ + instance.problem_name[instance.problem_name.rfind("/") + 1 :] + for k, instance in self.stat_instances[domain_name].items() + ] plt.figure() - if xaxis == 'action': + if xaxis == "action": # for instance in self.stat_instances[domain_name]: # print(instance) - x = [instance.action_space for k, instance in self.stat_instances[domain_name].items()] + x = [ + instance.action_space + for k, instance in self.stat_instances[domain_name].items() + ] plt.plot(x, y, label=label) # plt.plot(x, y, xlabel='\# Actions', ylabel='Time (s)', label='Actions vs Time') - elif xaxis == 'problem': - x = [instance.problem_name for k, instance in self.stat_instances[domain_name].items()] + elif xaxis == "problem": + x = [ + instance.problem_name + for k, instance in self.stat_instances[domain_name].items() + ] # plt.bar(x,y, xlabel='Problem', ylabel='Time (s)', label='Problems vs Time') plt.bar(x, y, label=label) # plt.show(block=False) plt.show() - diff --git a/pddl/bfs_planner.py b/pddl/bfs_planner.py index ffcf0d7b730f8044f070cdfc2e7b4c4437c015b7..71ac64cfa624d6c00504a65ef8b7c549654a471a 100644 --- a/pddl/bfs_planner.py +++ b/pddl/bfs_planner.py @@ -7,13 +7,12 @@ from pddl.state import applicable, apply class BFS_Planner(PDDLPlanner): - def __init__(self, verbose=False): super().__init__(verbose) - #----------------------------------------------- + # ----------------------------------------------- # Solve - #----------------------------------------------- + # ----------------------------------------------- def solve(self, domain, initial_state, goals): (positive_goals, negative_goals) = goals @@ -24,30 +23,42 @@ class BFS_Planner(PDDLPlanner): initial_state = fringe.pop(0) plan = fringe.pop(0) for act in domain: - if applicable(initial_state, act.positive_preconditions, act.negative_preconditions): - new_initial_state = apply(initial_state, act.add_effects, act.del_effects) + if applicable( + initial_state, + act.positive_preconditions, + act.negative_preconditions, + ): + new_initial_state = apply( + initial_state, act.add_effects, act.del_effects + ) if new_initial_state not in visited: - if applicable(new_initial_state, positive_goals, negative_goals): + if applicable( + new_initial_state, positive_goals, negative_goals + ): full_plan = [act] while plan: act, plan = plan full_plan.insert(0, act) - if self.stats: self.stats.nodes = len(visited) + if self.stats: + self.stats.nodes = len(visited) return full_plan visited.add(new_initial_state) fringe.append(new_initial_state) fringe.append((act, plan)) - if self.stats: self.stats.nodes = len(visited) + if self.stats: + self.stats.nodes = len(visited) return None + # ========================================== # Main # ========================================== -if __name__ == '__main__': +if __name__ == "__main__": import sys + domain = sys.argv[1] problem = sys.argv[2] planner = BFS_Planner() - plan, time = planner.solve_file(domain, problem) \ No newline at end of file + plan, time = planner.solve_file(domain, problem) diff --git a/pddl/heuristic.py b/pddl/heuristic.py index 770e45b60c7900bf620d45dbe68725a8dea4ff56..df7ebcbe7fc59bb6bcfd2c874ddd2ad7e5be6139 100644 --- a/pddl/heuristic.py +++ b/pddl/heuristic.py @@ -2,12 +2,12 @@ from pddl.benchmark import PlanningBenchmark, InstanceStats class Heuristic: - def __init__(self, stats=None): self.stats = stats def __call__(self, actions, initial_state, goals): - if self.stats: self.stats.h_calls += 1 + if self.stats: + self.stats.h_calls += 1 return self.h(actions, initial_state, goals) def h(self, domain, initial_state, goals): @@ -18,4 +18,4 @@ class Heuristic: :return: :rtype float """ - raise NotImplementedError("Unimplemented") \ No newline at end of file + raise NotImplementedError("Unimplemented") diff --git a/pddl/pddl_parser.py b/pddl/pddl_parser.py index 595f88ce9e546dc3af607c1fa92b21775576935b..6f4d81c1b19b472b8017a052114a3120051fa9bf 100644 --- a/pddl/pddl_parser.py +++ b/pddl/pddl_parser.py @@ -7,46 +7,46 @@ from pddl.action import Action class PDDLParser: - SUPPORTED_REQUIREMENTS = [':strips', ':negative-preconditions', ':typing'] + SUPPORTED_REQUIREMENTS = [":strips", ":negative-preconditions", ":typing"] # ------------------------------------------ # Tokens # ------------------------------------------ def scan_tokens(self, filename): - with open(filename,'r') as f: + with open(filename, "r") as f: # Remove single line comments - str = re.sub(r';.*$', '', f.read(), flags=re.MULTILINE).lower() + str = re.sub(r";.*$", "", f.read(), flags=re.MULTILINE).lower() # Tokenize stack = [] list = [] - for t in re.findall(r'[()]|[^\s()]+', str): - if t == '(': + for t in re.findall(r"[()]|[^\s()]+", str): + if t == "(": stack.append(list) list = [] - elif t == ')': + elif t == ")": if stack: l = list list = stack.pop() list.append(l) else: - raise Exception('Missing open parentheses') + raise Exception("Missing open parentheses") else: list.append(t) if stack: - raise Exception('Missing close parentheses') + raise Exception("Missing close parentheses") if len(list) != 1: - raise Exception('Malformed expression') + raise Exception("Malformed expression") return list[0] - #----------------------------------------------- + # ----------------------------------------------- # Parse domain - #----------------------------------------------- + # ----------------------------------------------- def parse_domain(self, domain_filename): tokens = self.scan_tokens(domain_filename) - if type(tokens) is list and tokens.pop(0) == 'define': - self.domain_name = 'unknown' + if type(tokens) is list and tokens.pop(0) == "define": + self.domain_name = "unknown" self.requirements = [] self.types = [] self.actions = [] @@ -54,59 +54,62 @@ class PDDLParser: while tokens: group = tokens.pop(0) t = group.pop(0) - if t == 'domain': + if t == "domain": self.domain_name = group[0] - elif t == ':requirements': + elif t == ":requirements": for req in group: if not req in self.SUPPORTED_REQUIREMENTS: - raise Exception('Requirement ' + req + ' not supported') + raise Exception("Requirement " + req + " not supported") self.requirements = group - elif t == ':predicates': + elif t == ":predicates": self.parse_predicates(group) - elif t == ':types': + elif t == ":types": self.types = group - elif t == ':action': + elif t == ":action": self.parse_action(group) - else: print(str(t) + ' is not recognized in domain') + else: + print(str(t) + " is not recognized in domain") else: - raise Exception('File ' + domain_filename + ' does not match domain pattern') + raise Exception( + "File " + domain_filename + " does not match domain pattern" + ) - #----------------------------------------------- + # ----------------------------------------------- # Parse predicates - #----------------------------------------------- + # ----------------------------------------------- def parse_predicates(self, group): for pred in group: predicate_name = pred.pop(0) if predicate_name in self.predicates: - raise Exception('Predicate ' + predicate_name + ' redefined') + raise Exception("Predicate " + predicate_name + " redefined") arguments = {} untyped_variables = [] while pred: t = pred.pop(0) - if t == '-': + if t == "-": if not untyped_variables: - raise Exception('Unexpected hyphen in predicates') + raise Exception("Unexpected hyphen in predicates") type = pred.pop(0) while untyped_variables: arguments[untyped_variables.pop(0)] = type else: untyped_variables.append(t) while untyped_variables: - arguments[untyped_variables.pop(0)] = 'object' + arguments[untyped_variables.pop(0)] = "object" self.predicates[predicate_name] = arguments - #----------------------------------------------- + # ----------------------------------------------- # Parse action - #----------------------------------------------- + # ----------------------------------------------- def parse_action(self, group): name = group.pop(0) if not type(name) is str: - raise Exception('Action without name definition') + raise Exception("Action without name definition") for act in self.actions: if act.name == name: - raise Exception('Action ' + name + ' redefined') + raise Exception("Action " + name + " redefined") parameters = [] positive_preconditions = [] negative_preconditions = [] @@ -114,39 +117,59 @@ class PDDLParser: del_effects = [] while group: t = group.pop(0) - if t == ':parameters': + if t == ":parameters": if not type(group) is list: - raise Exception('Error with ' + name + ' parameters') + raise Exception("Error with " + name + " parameters") parameters = [] untyped_parameters = [] p = group.pop(0) while p: t = p.pop(0) - if t == '-': + if t == "-": if not untyped_parameters: - raise Exception('Unexpected hyphen in ' + name + ' parameters') + raise Exception( + "Unexpected hyphen in " + name + " parameters" + ) ptype = p.pop(0) while untyped_parameters: parameters.append([untyped_parameters.pop(0), ptype]) else: untyped_parameters.append(t) while untyped_parameters: - parameters.append([untyped_parameters.pop(0), 'object']) - elif t == ':precondition': - self.split_propositions(group.pop(0), positive_preconditions, negative_preconditions, name, ' preconditions') - elif t == ':effect': - self.split_propositions(group.pop(0), add_effects, del_effects, name, ' effects') - else: print(str(t) + ' is not recognized in action') - self.actions.append(Action(name, tuple(parameters), frozenset(positive_preconditions), frozenset(negative_preconditions), frozenset(add_effects), frozenset(del_effects))) - - #----------------------------------------------- + parameters.append([untyped_parameters.pop(0), "object"]) + elif t == ":precondition": + self.split_propositions( + group.pop(0), + positive_preconditions, + negative_preconditions, + name, + " preconditions", + ) + elif t == ":effect": + self.split_propositions( + group.pop(0), add_effects, del_effects, name, " effects" + ) + else: + print(str(t) + " is not recognized in action") + self.actions.append( + Action( + name, + tuple(parameters), + frozenset(positive_preconditions), + frozenset(negative_preconditions), + frozenset(add_effects), + frozenset(del_effects), + ) + ) + + # ----------------------------------------------- # Parse problem - #----------------------------------------------- + # ----------------------------------------------- def parse_problem(self, problem_filename): tokens = self.scan_tokens(problem_filename) - if type(tokens) is list and tokens.pop(0) == 'define': - self.problem_name = 'unknown' + if type(tokens) is list and tokens.pop(0) == "define": + self.problem_name = "unknown" self.objects = dict() self.state = frozenset() self.positive_goals = frozenset() @@ -154,88 +177,93 @@ class PDDLParser: while tokens: group = tokens.pop(0) t = group[0] - if t == 'problem': + if t == "problem": self.problem_name = group[-1] - elif t == ':domain': + elif t == ":domain": if self.domain_name != group[-1]: - raise Exception('Different domain specified in problem file') - elif t == ':requirements': - pass # TODO - elif t == ':objects': + raise Exception("Different domain specified in problem file") + elif t == ":requirements": + pass # TODO + elif t == ":objects": group.pop(0) object_list = [] while group: - if group[0] == '-': + if group[0] == "-": group.pop(0) self.objects[group.pop(0)] = object_list object_list = [] else: object_list.append(group.pop(0)) if object_list: - if not 'object' in self.objects: - self.objects['object'] = [] - self.objects['object'] += object_list - elif t == ':init': + if not "object" in self.objects: + self.objects["object"] = [] + self.objects["object"] += object_list + elif t == ":init": group.pop(0) self.state = self.state_to_tuple(group) - elif t == ':goal': + elif t == ":goal": pos = [] neg = [] - self.split_propositions(group[1], pos, neg, '', 'goals') + self.split_propositions(group[1], pos, neg, "", "goals") self.positive_goals = frozenset(pos) self.negative_goals = frozenset(neg) - else: print(str(t) + ' is not recognized in problem') + else: + print(str(t) + " is not recognized in problem") else: - raise Exception('File ' + problem_filename + ' does not match problem pattern') + raise Exception( + "File " + problem_filename + " does not match problem pattern" + ) - #----------------------------------------------- + # ----------------------------------------------- # Split propositions - #----------------------------------------------- + # ----------------------------------------------- def split_propositions(self, group, pos, neg, name, part): if not type(group) is list: - raise Exception('Error with ' + name + part) - if group[0] == 'and': + raise Exception("Error with " + name + part) + if group[0] == "and": group.pop(0) else: group = [group] for proposition in group: - if proposition[0] == 'not': + if proposition[0] == "not": if len(proposition) != 2: - raise Exception('Unexpected not in ' + name + part) + raise Exception("Unexpected not in " + name + part) neg.append(tuple(proposition[-1])) else: pos.append(tuple(proposition)) - #----------------------------------------------- + # ----------------------------------------------- # State to tuple - #----------------------------------------------- + # ----------------------------------------------- def state_to_tuple(self, state): return frozenset(tuple(fact) for fact in state) + # ========================================== # Main # ========================================== -if __name__ == '__main__': +if __name__ == "__main__": import sys import pprint + domain = sys.argv[1] problem = sys.argv[2] parser = PDDLParser() - print('----------------------------') + print("----------------------------") pprint.pprint(parser.scan_tokens(domain)) - print('----------------------------') + print("----------------------------") pprint.pprint(parser.scan_tokens(problem)) - print('----------------------------') + print("----------------------------") parser.parse_domain(domain) parser.parse_problem(problem) - print('Domain name: ' + parser.domain_name) + print("Domain name: " + parser.domain_name) for act in parser.actions: print(act) - print('----------------------------') - print('Problem name: ' + parser.problem_name) - print('Objects: ' + str(parser.objects)) - print('State: ' + str(parser.state)) - print('Positive goals: ' + str(parser.positive_goals)) - print('Negative goals: ' + str(parser.negative_goals)) \ No newline at end of file + print("----------------------------") + print("Problem name: " + parser.problem_name) + print("Objects: " + str(parser.objects)) + print("State: " + str(parser.state)) + print("Positive goals: " + str(parser.positive_goals)) + print("Negative goals: " + str(parser.negative_goals)) diff --git a/pddl/pddl_planner.py b/pddl/pddl_planner.py index 45fb80318b7ddd28fd31e6ac22104c1ff9a2e4a7..c675f41bf2c78d90ac61223dc0d83646e5f72d21 100644 --- a/pddl/pddl_planner.py +++ b/pddl/pddl_planner.py @@ -5,7 +5,6 @@ import time class PDDLPlanner: - def __init__(self, verbose=False, collect_stats=False): self.verbose = verbose self.collect_benchmark = collect_stats @@ -16,7 +15,8 @@ class PDDLPlanner: # ----------------------------------------------- def solve_file(self, domainfile, problemfile): - if self.collect_benchmark: self.stats = PlanningBenchmark().get_instance(domainfile,problemfile) + if self.collect_benchmark: + self.stats = PlanningBenchmark().get_instance(domainfile, problemfile) # Parser start_time = time.time() @@ -28,23 +28,30 @@ class PDDLPlanner: return [], 0 # Grounding process ground_actions = self.grounding(parser) - if self.stats: self.stats.action_space = len(ground_actions) # compute stats - plan = self.solve(ground_actions, parser.state, (parser.positive_goals, parser.negative_goals)) + if self.stats: + self.stats.action_space = len(ground_actions) # compute stats + plan = self.solve( + ground_actions, parser.state, (parser.positive_goals, parser.negative_goals) + ) final_time = time.time() - start_time if self.verbose: - print('Time: ' + str(final_time) + 's') + print("Time: " + str(final_time) + "s") if plan: - print('plan:') + print("plan:") for act in plan: - print('(' + act.name + ''.join(' ' + p for p in act.parameters) + ')') + print( + "(" + act.name + "".join(" " + p for p in act.parameters) + ")" + ) else: - print('No plan was found') - if self.stats: self.stats.time = final_time + print("No plan was found") + if self.stats: + self.stats.time = final_time return plan, final_time def grounding(self, parser): ground_actions = [] - if self.verbose: start_time = time.time() + if self.verbose: + start_time = time.time() for action in parser.actions: for act in action.groundify(parser.objects): ground_actions.append(act) @@ -56,4 +63,4 @@ class PDDLPlanner: return ground_actions def solve(self, domain, initial_state, goals): - raise NotImplementedError("PDDL Planners need to implement solve") \ No newline at end of file + raise NotImplementedError("PDDL Planners need to implement solve") diff --git a/pddl/state.py b/pddl/state.py index 9ecd37925fa0748daee397fc3621fde6c5423e85..30b5bf31dce2af0b7ec37c8eec992d74de25e160 100644 --- a/pddl/state.py +++ b/pddl/state.py @@ -6,6 +6,7 @@ def applicable(state, positive, negative): return positive.issubset(state) and not negative.intersection(state) + # ----------------------------------------------- # Apply # ----------------------------------------------- @@ -14,6 +15,7 @@ def applicable(state, positive, negative): def apply(state, positive, negative): return frozenset(state.difference(negative).union(positive)) + # ----------------------------------------------- # regressable # ----------------------------------------------- @@ -22,11 +24,13 @@ def apply(state, positive, negative): def regressable(state, add_effects, del_effects): return add_effects.intersection(state) and del_effects.intersection(state) + # ----------------------------------------------- # regr # ----------------------------------------------- def regress(state, action): - return frozenset((state.difference(action.add_effects).union(action.positive_preconditions))) - + return frozenset( + (state.difference(action.add_effects).union(action.positive_preconditions)) + )