From f598bccd17ff6c1eacfdf6e0103714e655b1f413 Mon Sep 17 00:00:00 2001 From: hmp-anthony Date: Fri, 23 Aug 2024 14:00:56 +0100 Subject: [PATCH 01/42] arbitary domain --- filetofloorplan.ipynb | 273 ++++++++++++++++++++++++++++++++++++++++++ floorplan.txt | 5 + 2 files changed, 278 insertions(+) create mode 100644 filetofloorplan.ipynb create mode 100644 floorplan.txt diff --git a/filetofloorplan.ipynb b/filetofloorplan.ipynb new file mode 100644 index 000000000..589275b4a --- /dev/null +++ b/filetofloorplan.ipynb @@ -0,0 +1,273 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "id": "8db678b9-8332-4c2d-b5b6-345d1f1d2ae5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n", + " [0 1 1 2 1 1 1 1 1 1 1 1 1 1 0]\n", + " [0 0 1 0 1 0 1 0 2 2 2 2 2 2 0]\n", + " [0 0 1 0 1 1 2 1 1 1 1 0 0 0 0]\n", + " [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]\n", + "('Move', 'None') [1, 2] R\n", + "('Move', 'None') [1, 3] R\n", + "('Suck', 'None') [1, 3] R\n", + "('Move', 'None') [1, 4] R\n", + "('Move', 'None') [1, 5] R\n", + "('Move', 'None') [1, 6] R\n", + "('Move', 'None') [1, 7] R\n", + "('Move', 'None') [1, 8] R\n", + "('Move', 'None') [1, 9] R\n", + "('Move', 'None') [1, 10] R\n", + "('Move', 'None') [1, 11] R\n", + "('Move', 'None') [1, 12] R\n", + "('Move', 'None') [1, 13] R\n", + "('Move', 'None') [1, 13] R\n", + "('Move', 'Bump') [1, 13] D\n", + "('Move', 'None') [2, 13] D\n", + "('Suck', 'None') [2, 13] D\n", + "('Move', 'None') [2, 13] D\n", + "('Move', 'Bump') [2, 13] U\n", + "('Move', 'None') [1, 13] U\n", + "('Move', 'None') [1, 13] U\n", + "('Move', 'Bump') [1, 13] U\n", + "('Move', 'None') [1, 13] U\n", + "('Move', 'Bump') [1, 13] R\n", + "('Move', 'None') [1, 13] R\n", + "('Move', 'Bump') [1, 13] D\n", + "('Move', 'None') [2, 13] D\n", + "('Move', 'None') [2, 13] D\n", + "('Move', 'Bump') [2, 13] L\n", + "('Move', 'None') [2, 12] L\n", + "('Suck', 'None') [2, 12] L\n", + "('Move', 'None') [2, 11] L\n", + "('Suck', 'None') [2, 11] L\n", + "('Move', 'None') [2, 10] L\n", + "('Suck', 'None') [2, 10] L\n", + "('Move', 'None') [2, 9] L\n", + "('Suck', 'None') [2, 9] L\n", + "('Move', 'None') [2, 8] L\n", + "('Suck', 'None') [2, 8] L\n", + "('Move', 'None') [2, 8] L\n", + "('Move', 'Bump') [2, 8] R\n", + "('Move', 'None') [2, 9] R\n", + "('Move', 'None') [2, 10] R\n", + "('Move', 'None') [2, 11] R\n", + "('Move', 'None') [2, 12] R\n", + "('Move', 'None') [2, 13] R\n", + "('Move', 'None') [2, 13] R\n", + "('Move', 'Bump') [2, 13] D\n", + "('Move', 'None') [2, 13] D\n", + "('Move', 'Bump') [2, 13] D\n", + "('Move', 'None') [2, 13] D\n", + "('Move', 'Bump') [2, 13] D\n", + "('Move', 'None') [2, 13] D\n", + "('Move', 'Bump') [2, 13] D\n", + "('Move', 'None') [2, 13] D\n", + "('Move', 'Bump') [2, 13] R\n", + "('Move', 'None') [2, 13] R\n", + "('Move', 'Bump') [2, 13] U\n", + "('Move', 'None') [1, 13] U\n", + "('Move', 'None') [1, 13] U\n", + "('Move', 'Bump') [1, 13] R\n", + "('Move', 'None') [1, 13] R\n", + "('Move', 'Bump') [1, 13] R\n", + "('Move', 'None') [1, 13] R\n", + "('Move', 'Bump') [1, 13] U\n", + "('Move', 'None') [1, 13] U\n", + "('Move', 'Bump') [1, 13] U\n", + "('Move', 'None') [1, 13] U\n", + "('Move', 'Bump') [1, 13] L\n", + "('Move', 'None') [1, 12] L\n", + "('Move', 'None') [1, 11] L\n", + "('Move', 'None') [1, 10] L\n", + "('Move', 'None') [1, 9] L\n", + "('Move', 'None') [1, 8] L\n", + "('Move', 'None') [1, 7] L\n", + "('Move', 'None') [1, 6] L\n", + "('Move', 'None') [1, 5] L\n", + "('Move', 'None') [1, 4] L\n", + "('Move', 'None') [1, 3] L\n", + "('Move', 'None') [1, 2] L\n", + "('Move', 'None') [1, 1] L\n", + "('Move', 'None') [1, 1] L\n", + "('Move', 'Bump') [1, 1] R\n", + "('Move', 'None') [1, 2] R\n", + "('Move', 'None') [1, 3] R\n", + "('Move', 'None') [1, 4] R\n", + "('Move', 'None') [1, 5] R\n", + "('Move', 'None') [1, 6] R\n", + "('Move', 'None') [1, 7] R\n", + "('Move', 'None') [1, 8] R\n", + "('Move', 'None') [1, 9] R\n", + "('Move', 'None') [1, 10] R\n", + "('Move', 'None') [1, 11] R\n", + "('Move', 'None') [1, 12] R\n", + "('Move', 'None') [1, 13] R\n", + "('Move', 'None') [1, 13] R\n", + "('Move', 'Bump') [1, 13] R\n", + "('Move', 'None') [1, 13] R\n", + "('Move', 'Bump') [1, 13] R\n", + "('Move', 'None') [1, 13] R\n", + "[[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n", + " [0 1 1 1 1 1 1 1 1 1 1 1 1 1 0]\n", + " [0 0 1 0 1 0 1 0 1 1 1 1 1 1 0]\n", + " [0 0 1 0 1 1 2 1 1 1 1 0 0 0 0]\n", + " [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]\n", + "607\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "from agents import *\n", + "\n", + "class VacuumAgent(Agent):\n", + "\n", + " def __init__(self, program = None):\n", + " super().__init__(program)\n", + " self.location = [1,1]\n", + " self.direction = 'R' # 'R', 'L', 'U', 'D'\n", + "\n", + "def program(percept):\n", + " if percept == 2:\n", + " return ('Suck','None')\n", + " else:\n", + " bump = 'Bump' if agent.bump else 'None'\n", + " return ('Move', bump)\n", + "\n", + "class Environment:\n", + " \n", + " def __init__(self):\n", + " self.agents = []\n", + " \n", + " with open('floorplan.txt') as f:\n", + " floor_plan = np.array([list(map(int, line.strip())) for line in f])\n", + " self.floor_plan = floor_plan\n", + " \n", + " def percept(self, agent):\n", + " return self.floor_plan[agent.location[0]][agent.location[1]]\n", + "\n", + " def execute_action(self, agent, action):\n", + " if action[0] == 'Suck':\n", + " self.floor_plan[agent.location[0]][agent.location[1]] = 1\n", + " agent.performance += 100\n", + " if action[0] == 'Move':\n", + " agent.performance -= 1\n", + " if action[1] == 'Bump':\n", + " agent.direction = random.choice(['R', 'L', 'U', 'D'])\n", + " agent.bump = False\n", + " else:\n", + " agent.bump = self.move_agent(agent)\n", + "\n", + " def move_agent(self, agent):\n", + " if agent.direction == 'R':\n", + " loc = agent.location\n", + " if self.floor_plan[loc[0]][loc[1] + 1] == 0:\n", + " agent.bump = True\n", + " else:\n", + " agent.location[1] += 1\n", + " elif agent.direction == 'L':\n", + " loc = agent.location\n", + " if self.floor_plan[loc[0]][loc[1] - 1] == 0:\n", + " agent.bump = True\n", + " else:\n", + " agent.location[1] -= 1\n", + " elif agent.direction == 'U':\n", + " loc = agent.location\n", + " if self.floor_plan[loc[0] - 1][loc[1]] == 0:\n", + " agent.bump = True\n", + " else:\n", + " agent.location[0] -= 1\n", + " elif agent.direction == 'D':\n", + " loc = agent.location\n", + " if self.floor_plan[loc[0] + 1][loc[1]] == 0:\n", + " agent.bump = True\n", + " else:\n", + " agent.location[0] += 1\n", + " return agent.bump\n", + "\n", + " def step(self):\n", + " action = agent.program(self.percept(agent))\n", + " self.execute_action(self.agents[0], action)\n", + " print(action, self.agents[0].location, self.agents[0].direction)\n", + "\n", + " def run(self,steps=100):\n", + " for step in range(steps):\n", + " self.step()\n", + " \n", + " def display_floor(self):\n", + " print(self.floor_plan)\n", + "\n", + " def add_agent(self, agent):\n", + " self.agents.append(agent)\n", + "\n", + "\n", + "env = Environment()\n", + "agent = VacuumAgent(program)\n", + "env.add_agent(agent)\n", + "\n", + "env.display_floor()\n", + "env.run()\n", + "env.display_floor()\n", + "print(agent.performance)" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "7d77d786-792f-40b1-b863-6a6dcf40e1cb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr[1][1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9eae8f9a-6141-40d6-87a0-4ed3989b4ee7", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "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.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/floorplan.txt b/floorplan.txt new file mode 100644 index 000000000..cc4dbfe7a --- /dev/null +++ b/floorplan.txt @@ -0,0 +1,5 @@ +000000000000000 +011211111111110 +001010102222220 +001011211110000 +000000000000000 From edd3f5d8038e00442b06db5bedf94d257471c984 Mon Sep 17 00:00:00 2001 From: hmp-anthony Date: Fri, 23 Aug 2024 14:02:40 +0100 Subject: [PATCH 02/42] changed name --- filetofloorplan.ipynb => agent_generaldomain.ipynb | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename filetofloorplan.ipynb => agent_generaldomain.ipynb (100%) diff --git a/filetofloorplan.ipynb b/agent_generaldomain.ipynb similarity index 100% rename from filetofloorplan.ipynb rename to agent_generaldomain.ipynb From 6571f967571494eb2e8df58984602c975896a10f Mon Sep 17 00:00:00 2001 From: hmp-anthony Date: Fri, 23 Aug 2024 14:12:19 +0100 Subject: [PATCH 03/42] rerun example --- agent_generaldomain.ipynb | 104 +++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/agent_generaldomain.ipynb b/agent_generaldomain.ipynb index 589275b4a..add570645 100644 --- a/agent_generaldomain.ipynb +++ b/agent_generaldomain.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 4, + "execution_count": 2, "id": "8db678b9-8332-4c2d-b5b6-345d1f1d2ae5", "metadata": {}, "outputs": [ @@ -33,56 +33,11 @@ "('Move', 'None') [2, 13] D\n", "('Suck', 'None') [2, 13] D\n", "('Move', 'None') [2, 13] D\n", - "('Move', 'Bump') [2, 13] U\n", - "('Move', 'None') [1, 13] U\n", - "('Move', 'None') [1, 13] U\n", - "('Move', 'Bump') [1, 13] U\n", - "('Move', 'None') [1, 13] U\n", - "('Move', 'Bump') [1, 13] R\n", - "('Move', 'None') [1, 13] R\n", - "('Move', 'Bump') [1, 13] D\n", - "('Move', 'None') [2, 13] D\n", - "('Move', 'None') [2, 13] D\n", - "('Move', 'Bump') [2, 13] L\n", - "('Move', 'None') [2, 12] L\n", - "('Suck', 'None') [2, 12] L\n", - "('Move', 'None') [2, 11] L\n", - "('Suck', 'None') [2, 11] L\n", - "('Move', 'None') [2, 10] L\n", - "('Suck', 'None') [2, 10] L\n", - "('Move', 'None') [2, 9] L\n", - "('Suck', 'None') [2, 9] L\n", - "('Move', 'None') [2, 8] L\n", - "('Suck', 'None') [2, 8] L\n", - "('Move', 'None') [2, 8] L\n", - "('Move', 'Bump') [2, 8] R\n", - "('Move', 'None') [2, 9] R\n", - "('Move', 'None') [2, 10] R\n", - "('Move', 'None') [2, 11] R\n", - "('Move', 'None') [2, 12] R\n", - "('Move', 'None') [2, 13] R\n", - "('Move', 'None') [2, 13] R\n", - "('Move', 'Bump') [2, 13] D\n", - "('Move', 'None') [2, 13] D\n", - "('Move', 'Bump') [2, 13] D\n", - "('Move', 'None') [2, 13] D\n", - "('Move', 'Bump') [2, 13] D\n", - "('Move', 'None') [2, 13] D\n", - "('Move', 'Bump') [2, 13] D\n", - "('Move', 'None') [2, 13] D\n", "('Move', 'Bump') [2, 13] R\n", "('Move', 'None') [2, 13] R\n", "('Move', 'Bump') [2, 13] U\n", "('Move', 'None') [1, 13] U\n", "('Move', 'None') [1, 13] U\n", - "('Move', 'Bump') [1, 13] R\n", - "('Move', 'None') [1, 13] R\n", - "('Move', 'Bump') [1, 13] R\n", - "('Move', 'None') [1, 13] R\n", - "('Move', 'Bump') [1, 13] U\n", - "('Move', 'None') [1, 13] U\n", - "('Move', 'Bump') [1, 13] U\n", - "('Move', 'None') [1, 13] U\n", "('Move', 'Bump') [1, 13] L\n", "('Move', 'None') [1, 12] L\n", "('Move', 'None') [1, 11] L\n", @@ -97,6 +52,18 @@ "('Move', 'None') [1, 2] L\n", "('Move', 'None') [1, 1] L\n", "('Move', 'None') [1, 1] L\n", + "('Move', 'Bump') [1, 1] L\n", + "('Move', 'None') [1, 1] L\n", + "('Move', 'Bump') [1, 1] L\n", + "('Move', 'None') [1, 1] L\n", + "('Move', 'Bump') [1, 1] D\n", + "('Move', 'None') [1, 1] D\n", + "('Move', 'Bump') [1, 1] L\n", + "('Move', 'None') [1, 1] L\n", + "('Move', 'Bump') [1, 1] L\n", + "('Move', 'None') [1, 1] L\n", + "('Move', 'Bump') [1, 1] U\n", + "('Move', 'None') [1, 1] U\n", "('Move', 'Bump') [1, 1] R\n", "('Move', 'None') [1, 2] R\n", "('Move', 'None') [1, 3] R\n", @@ -111,16 +78,49 @@ "('Move', 'None') [1, 12] R\n", "('Move', 'None') [1, 13] R\n", "('Move', 'None') [1, 13] R\n", - "('Move', 'Bump') [1, 13] R\n", - "('Move', 'None') [1, 13] R\n", - "('Move', 'Bump') [1, 13] R\n", - "('Move', 'None') [1, 13] R\n", + "('Move', 'Bump') [1, 13] D\n", + "('Move', 'None') [2, 13] D\n", + "('Move', 'None') [2, 13] D\n", + "('Move', 'Bump') [2, 13] L\n", + "('Move', 'None') [2, 12] L\n", + "('Suck', 'None') [2, 12] L\n", + "('Move', 'None') [2, 11] L\n", + "('Suck', 'None') [2, 11] L\n", + "('Move', 'None') [2, 10] L\n", + "('Suck', 'None') [2, 10] L\n", + "('Move', 'None') [2, 9] L\n", + "('Suck', 'None') [2, 9] L\n", + "('Move', 'None') [2, 8] L\n", + "('Suck', 'None') [2, 8] L\n", + "('Move', 'None') [2, 8] L\n", + "('Move', 'Bump') [2, 8] D\n", + "('Move', 'None') [3, 8] D\n", + "('Move', 'None') [3, 8] D\n", + "('Move', 'Bump') [3, 8] L\n", + "('Move', 'None') [3, 7] L\n", + "('Move', 'None') [3, 6] L\n", + "('Suck', 'None') [3, 6] L\n", + "('Move', 'None') [3, 5] L\n", + "('Move', 'None') [3, 4] L\n", + "('Move', 'None') [3, 4] L\n", + "('Move', 'Bump') [3, 4] U\n", + "('Move', 'None') [2, 4] U\n", + "('Move', 'None') [1, 4] U\n", + "('Move', 'None') [1, 4] U\n", + "('Move', 'Bump') [1, 4] D\n", + "('Move', 'None') [2, 4] D\n", + "('Move', 'None') [3, 4] D\n", + "('Move', 'None') [3, 4] D\n", + "('Move', 'Bump') [3, 4] U\n", + "('Move', 'None') [2, 4] U\n", + "('Move', 'None') [1, 4] U\n", + "('Move', 'None') [1, 4] U\n", "[[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n", " [0 1 1 1 1 1 1 1 1 1 1 1 1 1 0]\n", " [0 0 1 0 1 0 1 0 1 1 1 1 1 1 0]\n", - " [0 0 1 0 1 1 2 1 1 1 1 0 0 0 0]\n", + " [0 0 1 0 1 1 1 1 1 1 1 0 0 0 0]\n", " [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]\n", - "607\n" + "708\n" ] } ], From 9a7a60f07e660d0d8a529a8ba6a65bb92b537caa Mon Sep 17 00:00:00 2001 From: hmp-anthony Date: Mon, 26 Aug 2024 19:55:40 +0100 Subject: [PATCH 04/42] path finder appears to be working --- polygon_obstacle_path_finder.ipynb | 154 ++++++++ search.ipynb | 576 +++++++++++++++++++---------- 2 files changed, 535 insertions(+), 195 deletions(-) create mode 100644 polygon_obstacle_path_finder.ipynb diff --git a/polygon_obstacle_path_finder.ipynb b/polygon_obstacle_path_finder.ipynb new file mode 100644 index 000000000..4d19e62d6 --- /dev/null +++ b/polygon_obstacle_path_finder.ipynb @@ -0,0 +1,154 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 202, + "id": "f18190c5-0169-4b33-9671-55043687159e", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAh8AAAGdCAYAAACyzRGfAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAmh0lEQVR4nO3de3CU9aH/8c+SkCVisgIKISWRVK0oIAIRR7Hn6MiUUgZlrNcicmB+bT2/UED64wCeonVEI7YiXviBOMdLf4rWdgj2MEc9lMNFKveAgYAhkYC5kARoks2FbJLd5/dHStpICASe/X53k/dr5pnpPvvdfT7zNO5+eC7f9TiO4wgAAMCQHrYDAACA7oXyAQAAjKJ8AAAAoygfAADAKMoHAAAwivIBAACMonwAAACjKB8AAMCoWNsBvi0UCqm0tFQJCQnyeDy24wAAgAvgOI5qamqUnJysHj06PrYRceWjtLRUKSkptmMAAICLUFRUpEGDBnU4JuLKR0JCgqSW8ImJiZbTAACAC+H3+5WSktL6Pd6RiCsfZ061JCYmUj4AAIgyF3LJBBecAgAAoygfAADAKMoHAAAwivIBAACMonwAAACjKB8AAMAoygcAADCK8gEAAIyifAAAAKMoHwAAwCjKBwAAMIryAQAAjKJ8AAAAoygfAADAKMoHAAAwivIBAACMirUdAAAAXDzHCaqq6nM1Nh5XXNxAXXHF9+XxxNiO1aFOH/nYsmWLJk2apOTkZHk8Hq1du/acYx9//HF5PB4tW7bsEiICAID2nDixRtu3D9aXX96lQ4d+oi+/vEvbtw/WiRNrbEfrUKfLR11dnUaMGKHly5d3OC4rK0vbt29XcnLyRYcDAADtO3FijXJz71cgUNxmfSBQotzc+yO6gHT6tMuECRM0YcKEDseUlJToF7/4hT777DNNnDjxosMBAICzOU5QBQWzJTntPSvJo4KCObryynsj8hSM69d8hEIhTZ06VfPmzdPQoUPPOz4QCCgQCLQ+9vv9bkcCAKBLqar6/KwjHm05CgSKVFX1ufr0udNQqgvn+t0uS5YsUWxsrGbNmnVB4zMzM+Xz+VqXlJQUtyMBANClNDYed3Wcaa6Wjz179uiVV17RO++8I4/Hc0GvWbhwoaqrq1uXoqIiNyMBANDlxMUNdHWcaa6Wj88//1wVFRVKTU1VbGysYmNjdezYMf3yl7/U4MGD232N1+tVYmJimwUAAJzbFVd8X17vIEnn+oe+R15viq644vsmY10wV6/5mDp1qsaNG9dm3fjx4zV16lRNnz7dzU0BANBteTwxuvbaV5Sbe79aCsg/XnjaUkiuvXZZRF5sKl1E+aitrVVBQUHr48LCQu3bt099+/ZVamqq+vXr12Z8z549lZSUpOuvv/7S0wIAAEnSVVfdp6FD/6iCgtltLj71egfp2muX6aqr7rOYrmOdLh+7d+/WXXfd1fp47ty5kqRp06bpnXfecS0YAADo2FVX3acrr7w36mY49TiO095Nwtb4/X75fD5VV1dz/QcAAFGiM9/f/LAcAAAwivIBAACMonwAAACjKB8AAMAoygcAADCK8gEAAIyifAAAAKMoHwAAwCjKBwAAMIryAQAAjKJ8AAAAoygfAADAKMoHAAAwivIBAACMonwAAACjKB8AAMAoygcAADCK8gEAAIyifAAAAKMoHwAAwCjKBwAAMIryAQAAjKJ8AAAAoygfAADAKMoHAAAwivIBAACMonwAAACjKB8AAMAoygcAADCK8gEAAIyifAAAAKMoHwAAwCjKBwAAMIryAQAAjKJ8AAAAoygfAADAKMoHAAAwivIBAACM6nT52LJliyZNmqTk5GR5PB6tXbu29bmmpibNnz9fw4cPV+/evZWcnKzHHntMpaWlbmYGAABRrNPlo66uTiNGjNDy5cvPeq6+vl7Z2dlatGiRsrOztWbNGuXl5emee+5xJSwAAIh+HsdxnIt+scejrKwsTZ48+Zxjdu3apTFjxujYsWNKTU0973v6/X75fD5VV1crMTHxYqMBAACDOvP9HfZrPqqrq+XxeHTFFVeEe1MAACAKxIbzzRsaGjR//nw98sgj52xBgUBAgUCg9bHf7w9nJAAAYFnYjnw0NTXpwQcflOM4WrFixTnHZWZmyufztS4pKSnhigQAACJAWMrHmeJx7NgxrV+/vsNzPwsXLlR1dXXrUlRUFI5IAAAgQrh+2uVM8cjPz9fGjRvVr1+/Dsd7vV55vV63YwAAgAjV6fJRW1urgoKC1seFhYXat2+f+vbtq4EDB+r+++9Xdna21q1bp2AwqLKyMklS3759FRcX515yAAAQlTp9q+2mTZt01113nbV+2rRp+vWvf620tLR2X7dx40bdeeed531/brUFACD6dOb7u9NH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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\"\"\" The goal of this code is to take a collection of polygons\n", + " with integer coordinates and returns a path that traverses \n", + " the obstacles \"\"\"\n", + "\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib.patches import Polygon\n", + "\n", + "polygons = [[(2,2), (4,2), (4,4), (2,4), (1,3)],\n", + " [(5,6), (8,6), (7,9)]]\n", + "\n", + "start = (1, 1)\n", + "end = (14, 14)\n", + "\n", + "polygon_plot = []\n", + "\n", + "for p in polygons:\n", + " polygon_plot.append(Polygon(p, facecolor = 'm'))\n", + "\n", + "\n", + "fig,ax = plt.subplots()\n", + "\n", + "# begin\n", + "ax.plot(start[0], start[1],'-ro')\n", + "# end\n", + "ax.plot(end[0], end[1],'-yo')\n", + "\n", + "for p in polygon_plot:\n", + " ax.add_patch(p)\n", + "\n", + "ax.set_xlim([0,15])\n", + "ax.set_ylim([0,15])\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 211, + "id": "17fb458e-a3ce-4af3-8632-3acf07fc658c", + "metadata": {}, + "outputs": [], + "source": [ + "def line_intersection(a, b, c, d):\n", + " denom = ((a[0] - b[0]) * (c[1] - d[1]) - (a[1] - b[1]) * (c[0] - d[0])) \n", + " if denom == 0:\n", + " return False\n", + " t = ((a[0] - c[0]) * (c[1] - d[1]) - (a[1] - c[1]) * (c[0] - d[0])) / denom\n", + " u = ((a[0] - c[0]) * (a[1] - b[1]) - (a[1] - c[1]) * (a[0] - b[0])) / denom\n", + " # check if line actually intersect\n", + " if (0 <= t and t <= 1 and 0 <= u and u <= 1):\n", + " return [a[0] + t * (b[0] - a[0]), a[1] + t * (b[1] - a[1])]\n", + " else: \n", + " return False\n", + "\n", + "def distance2(a,b):\n", + " return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2\n", + " \n", + "def find_reachable_states(p, S):\n", + " D = dict()\n", + " for obstacle in S:\n", + " for u in obstacle:\n", + " # length^2 of line segment (p,u)\n", + " r = distance2(p, u)\n", + " D[(p,u)] = True \n", + " # does the line sigment (p, u) intersect \n", + " # a line segment belonging to another polygon?\n", + " for other_obstacle in S:\n", + " N = len(other_obstacle)\n", + " for i in range(N):\n", + " if(distance2(p,other_obstacle[i])>r):\n", + " continue\n", + " if(i < N-1):\n", + " z = line_intersection(p, u, other_obstacle[i], other_obstacle[i+1])\n", + " if(i == N-1):\n", + " \n", + " if(z):\n", + " r2 = distance2(p,z)\n", + " if(r2 < r):\n", + " D[(p,u)] = False\n", + " \n", + " \n", + " return D\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 212, + "id": "e9934801-8b1b-4695-b289-8c796639a00f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{((1, 1), (2, 2)): True, ((1, 1), (4, 2)): True, ((1, 1), (4, 4)): False, ((1, 1), (2, 4)): True, ((1, 1), (1, 3)): True, ((1, 1), (5, 6)): False, ((1, 1), (8, 6)): False, ((1, 1), (7, 9)): False}\n" + ] + } + ], + "source": [ + "DD = find_reachable_states(start, polygons)\n", + "print(DD)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e918ef0c-d39e-4150-aea3-d7476238a9c5", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "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.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/search.ipynb b/search.ipynb index caf231dcc..ce731606b 100644 --- a/search.ipynb +++ b/search.ipynb @@ -3,7 +3,10 @@ { "cell_type": "markdown", "metadata": { - "collapsed": true + "collapsed": true, + "jupyter": { + "outputs_hidden": true + } }, "source": [ "# Solving problems by Searching\n", @@ -13,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 50, "metadata": { "scrolled": true }, @@ -89,7 +92,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 51, "metadata": {}, "outputs": [], "source": [ @@ -115,7 +118,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 52, "metadata": {}, "outputs": [ { @@ -123,33 +126,45 @@ "text/html": [ "\n", - "\n", + "\n", "\n", "\n", " \n", " \n", " + + + + + + + + + + + +
+
+ + diff --git a/polygon_obstacle_path_finder.ipynb b/polygon_obstacle_path_finder.ipynb index cc0c11299..40ffd7c10 100644 --- a/polygon_obstacle_path_finder.ipynb +++ b/polygon_obstacle_path_finder.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 85, + "execution_count": 58, "id": "f18190c5-0169-4b33-9671-55043687159e", "metadata": { "scrolled": true @@ -67,7 +67,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 59, "id": "17fb458e-a3ce-4af3-8632-3acf07fc658c", "metadata": {}, "outputs": [], @@ -134,7 +134,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 60, "id": "43f49db3-ed68-4235-bdcc-2f34a33a65d2", "metadata": {}, "outputs": [], @@ -144,7 +144,7 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 61, "id": "7568c467-f23b-4192-8535-a848877b1c36", "metadata": {}, "outputs": [], @@ -157,7 +157,7 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 62, "id": "6f5b6af2-5d8c-44ab-98aa-c1c0e847377c", "metadata": {}, "outputs": [], @@ -174,7 +174,7 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": 63, "id": "10f27135-59ff-4a8b-937f-009072e0cc41", "metadata": { "jupyter": { @@ -223,7 +223,7 @@ }, { "cell_type": "code", - "execution_count": 91, + "execution_count": 64, "id": "f7930f26-5d68-4426-8051-be7bed5034d3", "metadata": {}, "outputs": [], @@ -247,26 +247,108 @@ }, { "cell_type": "code", - "execution_count": 92, + "execution_count": 88, "id": "685bd626-9ca5-4646-bff4-5fcbded6b38a", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "883 μs ± 119 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "uniform_cost_search_route = path_states(uniform_cost_search(route_problem)) " + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "feae84b2-f1a3-4f1a-a3d6-87bcc86ec1e1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "471 μs ± 31.6 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "breadth_first_search_route = path_states(breadth_first_search(route_problem))" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "id": "7342b554-231f-4641-9df0-2d66ec08428f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.53 ms ± 109 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "depth_limited_search_route = path_states(depth_limited_search(route_problem))" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "78b31841-65fd-4e1e-9eeb-97354c24982a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "22 ms ± 445 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "astar_search_route = path_states(astar_tree_search(route_problem))" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "d187c172-2466-4429-a797-19c8022fc5ca", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "307 μs ± 7.37 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" + ] + } + ], "source": [ - "uniform_cost_search_route = path_states(uniform_cost_search(route_problem)) \n", - "breadth_first_search_route = path_states(breadth_first_search(route_problem))\n", - "astar_search_route = path_states(astar_tree_search(route_problem))\n", + "%%timeit\n", "weighted_astar_search_route = path_states(weighted_astar_search(route_problem))" ] }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 82, "id": "d9e6f5f7-943c-46f0-8062-c091d43aa81b", "metadata": {}, "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -296,6 +378,7 @@ "\n", "plt.plot(*zip(*uniform_cost_search_route), color='r')\n", "plt.plot(*zip(*breadth_first_search_route), color='b')\n", + "plt.plot(*zip(*depth_limited_search_route), color='c')\n", "plt.plot(*zip(*astar_search_route), color='g')\n", "plt.plot(*zip(*weighted_astar_search_route), color='m')\n", "\n", @@ -307,7 +390,7 @@ }, { "cell_type": "code", - "execution_count": 95, + "execution_count": 70, "id": "af5b8345-1acc-4a5c-8dff-6a7b8e038070", "metadata": {}, "outputs": [], @@ -322,7 +405,7 @@ }, { "cell_type": "code", - "execution_count": 96, + "execution_count": 83, "id": "4c39f050-e08d-4ffa-9691-bc7d136385f9", "metadata": {}, "outputs": [ @@ -332,6 +415,7 @@ "text": [ "20.37120691423263\n", "25.162277660168378\n", + "34.5672465993875\n", "20.37120691423263\n", "20.62154290428604\n" ] @@ -340,21 +424,56 @@ "source": [ "uniform_cost_search_cost = calculate_path_cost(uniform_cost_search_route)\n", "breadth_first_search_cost = calculate_path_cost(breadth_first_search_route)\n", + "depth_limited_search_cost = calculate_path_cost(depth_limited_search_route)\n", "astar_search_cost = calculate_path_cost(astar_search_route)\n", "weighted_astar_search_cost = calculate_path_cost(weighted_astar_search_route)\n", "print(uniform_cost_search_cost)\n", "print(breadth_first_search_cost)\n", + "print(depth_limited_search_cost)\n", "print(astar_search_cost)\n", "print(weighted_astar_search_cost)" ] }, { "cell_type": "code", - "execution_count": null, - "id": "6a9e1f3b-0612-4140-bdbe-8cb495765dbf", + "execution_count": 87, + "id": "19fdecf7-4c90-4153-9b98-39800afe812c", "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "uniform_cost_search:\n", + " 319 nodes | 45 goal | 20 cost | 51 actions | RouteProblem((1, 1), (14, 14))\n", + " 319 nodes | 45 goal | 20 cost | 51 actions | TOTAL\n", + "\n", + "breadth_first_search:\n", + " 207 nodes | 208 goal | 25 cost | 34 actions | RouteProblem((1, 1), (14, 14))\n", + " 207 nodes | 208 goal | 25 cost | 34 actions | TOTAL\n", + "\n", + "depth_limited_search:\n", + " 618 nodes | 570 goal | 35 cost | 93 actions | RouteProblem((1, 1), (14, 14))\n", + " 618 nodes | 570 goal | 35 cost | 93 actions | TOTAL\n", + "\n", + "astar_tree_search:\n", + " 2,819 nodes | 358 goal | 20 cost | 364 actions | RouteProblem((1, 1), (14, 14))\n", + " 2,819 nodes | 358 goal | 20 cost | 364 actions | TOTAL\n", + "\n", + "weighted_astar_search:\n", + " 70 nodes | 11 goal | 21 cost | 17 actions | RouteProblem((1, 1), (14, 14))\n", + " 70 nodes | 11 goal | 21 cost | 17 actions | TOTAL\n", + "\n" + ] + } + ], + "source": [ + "report([uniform_cost_search, \n", + " breadth_first_search, \n", + " depth_limited_search,\n", + " astar_tree_search, \n", + " weighted_astar_search], [route_problem])" + ] } ], "metadata": { diff --git a/search_2.py b/search_2.py index 15d5832d9..10c923b51 100644 --- a/search_2.py +++ b/search_2.py @@ -275,3 +275,34 @@ def h(self, node): def straight_line_distance(A, B): "Straight-line distance between two points." return sum(abs(a - b)**2 for (a, b) in zip(A, B)) ** 0.5 + +class CountCalls: + """Delegate all attribute gets to the object, and count them in ._counts""" + def __init__(self, obj): + self._object = obj + self._counts = Counter() + + def __getattr__(self, attr): + "Delegate to the original object, after incrementing a counter." + self._counts[attr] += 1 + return getattr(self._object, attr) + + +def report(searchers, problems, verbose=True): + """Show summary statistics for each searcher (and on each problem unless verbose is false).""" + for searcher in searchers: + print(searcher.__name__ + ':') + total_counts = Counter() + for p in problems: + prob = CountCalls(p) + soln = searcher(prob) + counts = prob._counts; + counts.update(actions=len(soln), cost=soln.path_cost) + total_counts += counts + if verbose: report_counts(counts, str(p)[:40]) + report_counts(total_counts, 'TOTAL\n') + +def report_counts(counts, name): + """Print one line of the counts report.""" + print('{:9,d} nodes |{:9,d} goal |{:5.0f} cost |{:8,d} actions | {}'.format( + counts['result'], counts['is_goal'], counts['cost'], counts['actions'], name)) From 380ac05b59d71c41230211bf39bbc554443bf52f Mon Sep 17 00:00:00 2001 From: hmp-anthony Date: Fri, 6 Sep 2024 12:11:57 +0100 Subject: [PATCH 19/42] added cannibals --- .search_2.py.swp | Bin 0 -> 16384 bytes Cannibals.html | 7621 ++++++++++++++++++++++++++++++++++++++++++++++ Cannibals.ipynb | 114 + search4e.ipynb | 96 +- 4 files changed, 7766 insertions(+), 65 deletions(-) create mode 100644 .search_2.py.swp create mode 100644 Cannibals.html create mode 100644 Cannibals.ipynb diff --git a/.search_2.py.swp b/.search_2.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..5c9a4a1ba4ec43480e234348a573cf9c2a55c00d GIT binary patch literal 16384 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 literal 0 HcmV?d00001 diff --git a/Cannibals.html b/Cannibals.html new file mode 100644 index 000000000..0e0546abf --- /dev/null +++ b/Cannibals.html @@ -0,0 +1,7621 @@ + + + + + +Cannibals + + + + + + + + + + + + +
+
+ + diff --git a/Cannibals.ipynb b/Cannibals.ipynb new file mode 100644 index 000000000..0b5e9f135 --- /dev/null +++ b/Cannibals.ipynb @@ -0,0 +1,114 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 19, + "id": "dc5a163b-a0c6-46ac-a6b8-3d896331c6f4", + "metadata": {}, + "outputs": [], + "source": [ + "from search_2 import *" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "15f03785-bd50-4326-bd47-99a202c8e1e0", + "metadata": {}, + "outputs": [], + "source": [ + "def add(xs,ys):\n", + " return tuple(x + y for x, y in zip(xs, ys))\n", + "\n", + "\n", + "class Cannibals(Problem):\n", + " def __init__(self, initial=(3, 3, 1, 0, 0, 0), goal=(0, 0, 0, 1, 3, 3), obstacles=(), **kwds):\n", + " Problem.__init__(self, initial=initial, goal=goal, obstacles=set(), **kwds)\n", + " # The first index is the change in cannibals from\n", + " # the left hand side. The second index is the \n", + " # change in missionaries from the left hand side.\n", + " self.directions = [(-1, -1, -1, 1, 1, 1),\n", + " (1, 1, 1, -1, -1, -1),\n", + " (-2, 0, -1, 1, 2, 0),\n", + " (2, 0, 1, -1, -2, 0),\n", + " (0, -2, -1, 1, 0, 2),\n", + " (0, 2, 1, -1, 0, -2),\n", + " (-1, 0, -1, 1, 1, 0),\n", + " (1, 0, 1, -1, -1, 0),\n", + " (0, -1, -1, 1, 0, 1),\n", + " (0, 1, 1, -1, 0, -1)]\n", + " \n", + " def result(self, state, action):\n", + " return add(action,state)\n", + " \n", + " def actions(self, state):\n", + " legit_directions = set()\n", + " for d in self.directions:\n", + " result = add(d,state)\n", + " # if more cannibals than missionaries\n", + " if(state[0] > state[1] or state[3] > state[4]):\n", + " continue\n", + " # if there are negative numbers / more than 3\n", + " # of each canns missionaries\n", + " if(state[0] < 0 or state[1] < 0 or state[0] > 3 or state[1] > 3):\n", + " continue\n", + " # now we need to check boat status\n", + " b1 = state[2]\n", + " if(b1 < 0 or b1 > 1):\n", + " continue\n", + " b2 = state[3]\n", + " if(b2 < 0 or b2 > 1):\n", + " continue \n", + " if(b1 == 1):\n", + " if(b2 != 0):\n", + " continue\n", + " if(b2 == 1):\n", + " if(b1 != 0):\n", + " continue\n", + " # if we reach this point then we have a ligit state\n", + " legit_directions.add(d)\n", + " return legit_directions\n" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "6d591417-9225-4eba-bea5-9bb87268f2e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(3, 3, 1, 0, 0, 0), (2, 2, 0, 1, 1, 1), (2, 3, 1, 0, 1, 0), (1, 2, 0, 1, 2, 1), (2, 2, 1, 0, 1, 1), (0, 2, 0, 1, 3, 1), (1, 2, 1, 0, 2, 1), (0, 1, 0, 1, 3, 2), (1, 1, 1, 0, 2, 2), (0, 0, 0, 1, 3, 3)]\n" + ] + } + ], + "source": [ + "problem = Cannibals()\n", + "print(path_states(astar_search(problem)))" + ] + } + ], + "metadata": { + "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.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/search4e.ipynb b/search4e.ipynb index 7c636f2e7..434297694 100644 --- a/search4e.ipynb +++ b/search4e.ipynb @@ -17,7 +17,7 @@ }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -100,7 +100,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -142,7 +142,7 @@ }, { "cell_type": "code", - "execution_count": 356, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -238,7 +238,7 @@ }, { "cell_type": "code", - "execution_count": 234, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -300,26 +300,6 @@ " return failure" ] }, - { - "cell_type": "code", - "execution_count": 236, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['N', 'I', 'V', 'U', 'B', 'F', 'S', 'O', 'Z', 'A', 'T', 'L']" - ] - }, - "execution_count": 236, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "path_states(depth_first_recursive_search(r2))" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -329,7 +309,7 @@ }, { "cell_type": "code", - "execution_count": 412, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -360,7 +340,7 @@ }, { "cell_type": "code", - "execution_count": 413, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -416,7 +396,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -426,7 +406,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -462,7 +442,7 @@ }, { "cell_type": "code", - "execution_count": 398, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -496,7 +476,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -527,7 +507,7 @@ }, { "cell_type": "code", - "execution_count": 400, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -554,7 +534,7 @@ }, { "cell_type": "code", - "execution_count": 232, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -563,7 +543,7 @@ "['A', 'S', 'R', 'P', 'B']" ] }, - "execution_count": 232, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -574,7 +554,7 @@ }, { "cell_type": "code", - "execution_count": 233, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -583,7 +563,7 @@ "['A', 'S', 'F', 'B']" ] }, - "execution_count": 233, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -603,7 +583,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ @@ -629,7 +609,9 @@ " def actions(self, state):\n", " \"\"\"You can move one cell in any of `directions` to a non-obstacle cell.\"\"\"\n", " x, y = state\n", - " return {(x + dx, y + dy) for (dx, dy) in self.directions} - self.obstacles\n", + " Z = {(x + dx, y + dy) for (dx, dy) in self.directions} - self.obstacles\n", + " print(type(Z))\n", + " return Z\n", " \n", "class ErraticVacuum(Problem):\n", " def actions(self, state): \n", @@ -644,7 +626,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -1274,9 +1256,7 @@ { "cell_type": "code", "execution_count": 38, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1427,9 +1407,7 @@ { "cell_type": "code", "execution_count": 41, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1554,9 +1532,7 @@ { "cell_type": "code", "execution_count": 42, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1802,9 +1778,7 @@ { "cell_type": "code", "execution_count": 46, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1890,9 +1864,7 @@ { "cell_type": "code", "execution_count": 47, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1987,9 +1959,7 @@ { "cell_type": "code", "execution_count": 48, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -2082,9 +2052,7 @@ { "cell_type": "code", "execution_count": 49, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -2337,9 +2305,7 @@ { "cell_type": "code", "execution_count": 78, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -2630,7 +2596,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -2644,9 +2610,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.0" + "version": "3.11.2" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } From abba7c26e6d96cc2eace3426d1038b4a623ace66 Mon Sep 17 00:00:00 2001 From: hmp-anthony Date: Fri, 6 Sep 2024 14:10:41 +0100 Subject: [PATCH 20/42] working on iterative_lengthening --- .search_2.py.swp | Bin 16384 -> 0 bytes iterative_lengthening_search.ipynb | 168 +++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) delete mode 100644 .search_2.py.swp create mode 100644 iterative_lengthening_search.ipynb diff --git a/.search_2.py.swp b/.search_2.py.swp deleted file mode 100644 index 5c9a4a1ba4ec43480e234348a573cf9c2a55c00d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 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 diff --git a/iterative_lengthening_search.ipynb b/iterative_lengthening_search.ipynb new file mode 100644 index 000000000..a58e20964 --- /dev/null +++ b/iterative_lengthening_search.ipynb @@ -0,0 +1,168 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 51, + "id": "ef35fc56-180a-4d1a-9099-bed021f6e0ee", + "metadata": {}, + "outputs": [], + "source": [ + "from search_2 import *\n", + "\n", + "def best_first_limited_cost_search(problem, f, cost_limit):\n", + " node = Node(problem.initial)\n", + " frontier = PriorityQueue([node], key=f)\n", + " reached = {problem.initial : node}\n", + " result = failure\n", + " lowest_path_cost = None;\n", + " while frontier:\n", + " node = frontier.pop()\n", + " if problem.is_goal(node.state):\n", + " # we found a solution\n", + " return node\n", + " for child in expand(problem, node):\n", + " s = child.state\n", + " # if the path_cost is larger than cost_limit, we need to ignore this child.\n", + " if child.path_cost > cost_limit:\n", + " print(child.state, child.path_cost) \n", + " if lowest_path_cost == None or child.path_cost < lowest_path_cost:\n", + " lowest_path_cost = child.path_cost\n", + " result = Node('cost_limit_reached', path_cost = lowest_path_cost)\n", + " elif s not in reached or child.path_cost < reached[s].path_cost:\n", + " reached[s] = child\n", + " frontier.add(child)\n", + " return result\n", + "\n", + "def iterative_lengthening_search(problem):\n", + " print(\"first iteration\")\n", + " n = best_first_limited_cost_search(problem, g, 0)\n", + " print('\\t', n.path_cost)\n", + " \n", + " print(\"second iteration\")\n", + " n = best_first_limited_cost_search(problem, g, n.path_cost)\n", + " print('\\t', n.path_cost)\n", + " \n", + " print(\"third iteration\")\n", + " n = best_first_limited_cost_search(problem, g, 1000)\n", + " print('\\t', n.path_cost)\n", + " return n" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "99015fa1-471a-4149-bfe1-4bd7f12671fd", + "metadata": {}, + "outputs": [], + "source": [ + "romania = Map(\n", + " {('O', 'Z'): 71, ('O', 'S'): 151, ('A', 'Z'): 75, ('A', 'S'): 140, ('A', 'T'): 118, \n", + " ('L', 'T'): 111, ('L', 'M'): 70, ('D', 'M'): 75, ('C', 'D'): 120, ('C', 'R'): 146, \n", + " ('C', 'P'): 138, ('R', 'S'): 80, ('F', 'S'): 99, ('B', 'F'): 211, ('B', 'P'): 101, \n", + " ('B', 'G'): 90, ('B', 'U'): 85, ('H', 'U'): 98, ('E', 'H'): 86, ('U', 'V'): 142, \n", + " ('I', 'V'): 92, ('I', 'N'): 87, ('P', 'R'): 97},\n", + " {'A': ( 76, 497), 'B': (400, 327), 'C': (246, 285), 'D': (160, 296), 'E': (558, 294), \n", + " 'F': (285, 460), 'G': (368, 257), 'H': (548, 355), 'I': (488, 535), 'L': (162, 379),\n", + " 'M': (160, 343), 'N': (407, 561), 'O': (117, 580), 'P': (311, 372), 'R': (227, 412),\n", + " 'S': (187, 463), 'T': ( 83, 414), 'U': (471, 363), 'V': (535, 473), 'Z': (92, 539)})\n", + "\n", + "\n", + "r0 = RouteProblem('A', 'A', map=romania)\n", + "r1 = RouteProblem('A', 'B', map=romania)\n", + "r2 = RouteProblem('N', 'L', map=romania)\n", + "r3 = RouteProblem('E', 'T', map=romania)\n", + "r4 = RouteProblem('O', 'M', map=romania)" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "9e580734-b4f8-4d48-82d2-adcac10f8714", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "first iteration\n", + "Z 75\n", + "S 140\n", + "T 118\n", + "\t 75\n", + "second iteration\n", + "S 140\n", + "T 118\n", + "O 146\n", + "A 150\n", + "\t 118\n", + "third iteration\n", + "\t 418\n" + ] + }, + { + "data": { + "text/plain": [ + "['A', 'S', 'R', 'P', 'B']" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "path_states(iterative_lengthening_search(r1))" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "8b501fbc-64e9-48c4-81d1-03af28b8c8c6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['A', 'S', 'R', 'P', 'B']\n", + "418\n" + ] + } + ], + "source": [ + "n = uniform_cost_search(r1)\n", + "print(path_states(n))\n", + "print(n.path_cost)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09f683d4-d27e-4b9b-b279-bb7c46673870", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "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.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From ec662d67e46aa10b88eeb10afc25e39d4c630a18 Mon Sep 17 00:00:00 2001 From: hmp-anthony Date: Fri, 6 Sep 2024 14:43:16 +0100 Subject: [PATCH 21/42] finished ILS --- iterative_lengthening_search.ipynb | 78 +++++++----------------------- 1 file changed, 18 insertions(+), 60 deletions(-) diff --git a/iterative_lengthening_search.ipynb b/iterative_lengthening_search.ipynb index a58e20964..ec8a9c0b3 100644 --- a/iterative_lengthening_search.ipynb +++ b/iterative_lengthening_search.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 51, + "execution_count": 127, "id": "ef35fc56-180a-4d1a-9099-bed021f6e0ee", "metadata": {}, "outputs": [], @@ -24,33 +24,28 @@ " s = child.state\n", " # if the path_cost is larger than cost_limit, we need to ignore this child.\n", " if child.path_cost > cost_limit:\n", - " print(child.state, child.path_cost) \n", " if lowest_path_cost == None or child.path_cost < lowest_path_cost:\n", " lowest_path_cost = child.path_cost\n", - " result = Node('cost_limit_reached', path_cost = lowest_path_cost)\n", + " result = Node('cost_limit_reached',\n", + " path_cost = lowest_path_cost)\n", " elif s not in reached or child.path_cost < reached[s].path_cost:\n", " reached[s] = child\n", " frontier.add(child)\n", " return result\n", "\n", "def iterative_lengthening_search(problem):\n", - " print(\"first iteration\")\n", " n = best_first_limited_cost_search(problem, g, 0)\n", - " print('\\t', n.path_cost)\n", - " \n", - " print(\"second iteration\")\n", - " n = best_first_limited_cost_search(problem, g, n.path_cost)\n", - " print('\\t', n.path_cost)\n", - " \n", - " print(\"third iteration\")\n", - " n = best_first_limited_cost_search(problem, g, 1000)\n", - " print('\\t', n.path_cost)\n", + " iteration = 0\n", + " while(n.state == 'cost_limit_reached'):\n", + " n = best_first_limited_cost_search(problem, g, n.path_cost)\n", + " iteration = iteration + 1\n", + " print(iteration)\n", " return n" ] }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 134, "id": "99015fa1-471a-4149-bfe1-4bd7f12671fd", "metadata": {}, "outputs": [], @@ -76,7 +71,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 135, "id": "9e580734-b4f8-4d48-82d2-adcac10f8714", "metadata": {}, "outputs": [ @@ -84,64 +79,27 @@ "name": "stdout", "output_type": "stream", "text": [ - "first iteration\n", - "Z 75\n", - "S 140\n", - "T 118\n", - "\t 75\n", - "second iteration\n", - "S 140\n", - "T 118\n", - "O 146\n", - "A 150\n", - "\t 118\n", - "third iteration\n", - "\t 418\n" + "23\n", + "35\n", + "37\n" ] }, { "data": { "text/plain": [ - "['A', 'S', 'R', 'P', 'B']" + "['E', 'H', 'U', 'B', 'P', 'R', 'S', 'A', 'T']" ] }, - "execution_count": 53, + "execution_count": 135, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "path_states(iterative_lengthening_search(r1))" + "path_states(iterative_lengthening_search(r1))\n", + "path_states(iterative_lengthening_search(r2))\n", + "path_states(iterative_lengthening_search(r3))" ] - }, - { - "cell_type": "code", - "execution_count": 54, - "id": "8b501fbc-64e9-48c4-81d1-03af28b8c8c6", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['A', 'S', 'R', 'P', 'B']\n", - "418\n" - ] - } - ], - "source": [ - "n = uniform_cost_search(r1)\n", - "print(path_states(n))\n", - "print(n.path_cost)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "09f683d4-d27e-4b9b-b279-bb7c46673870", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { From 2fc2a65a65622397b230d398a09194a1fd556b24 Mon Sep 17 00:00:00 2001 From: hmp-anthony Date: Fri, 6 Sep 2024 15:08:52 +0100 Subject: [PATCH 22/42] updated prints --- iterative_lengthening_search.html | 7629 ++++++++++++++++++++++++++++ iterative_lengthening_search.ipynb | 141 +- 2 files changed, 7760 insertions(+), 10 deletions(-) create mode 100644 iterative_lengthening_search.html diff --git a/iterative_lengthening_search.html b/iterative_lengthening_search.html new file mode 100644 index 000000000..d9360d980 --- /dev/null +++ b/iterative_lengthening_search.html @@ -0,0 +1,7629 @@ + + + + + +iterative_lengthening_search + + + + + + + + + + + + +
+
+ + diff --git a/iterative_lengthening_search.ipynb b/iterative_lengthening_search.ipynb index ec8a9c0b3..50f4151b0 100644 --- a/iterative_lengthening_search.ipynb +++ b/iterative_lengthening_search.ipynb @@ -2,13 +2,17 @@ "cells": [ { "cell_type": "code", - "execution_count": 127, + "execution_count": 36, "id": "ef35fc56-180a-4d1a-9099-bed021f6e0ee", "metadata": {}, "outputs": [], "source": [ "from search_2 import *\n", "\n", + "# My implementation of iterative lengthening search from problem 3.17.\n", + "# I don't really see the point in this algorithm - just use uniform-cost search?\n", + "# Maybe it is for people who want partial solutions???\n", + "\n", "def best_first_limited_cost_search(problem, f, cost_limit):\n", " node = Node(problem.initial)\n", " frontier = PriorityQueue([node], key=f)\n", @@ -27,7 +31,8 @@ " if lowest_path_cost == None or child.path_cost < lowest_path_cost:\n", " lowest_path_cost = child.path_cost\n", " result = Node('cost_limit_reached',\n", - " path_cost = lowest_path_cost)\n", + " path_cost = lowest_path_cost,\n", + " parent = node)\n", " elif s not in reached or child.path_cost < reached[s].path_cost:\n", " reached[s] = child\n", " frontier.add(child)\n", @@ -39,13 +44,14 @@ " while(n.state == 'cost_limit_reached'):\n", " n = best_first_limited_cost_search(problem, g, n.path_cost)\n", " iteration = iteration + 1\n", + " print(path_states(n))\n", " print(iteration)\n", " return n" ] }, { "cell_type": "code", - "execution_count": 134, + "execution_count": 37, "id": "99015fa1-471a-4149-bfe1-4bd7f12671fd", "metadata": {}, "outputs": [], @@ -61,8 +67,6 @@ " 'M': (160, 343), 'N': (407, 561), 'O': (117, 580), 'P': (311, 372), 'R': (227, 412),\n", " 'S': (187, 463), 'T': ( 83, 414), 'U': (471, 363), 'V': (535, 473), 'Z': (92, 539)})\n", "\n", - "\n", - "r0 = RouteProblem('A', 'A', map=romania)\n", "r1 = RouteProblem('A', 'B', map=romania)\n", "r2 = RouteProblem('N', 'L', map=romania)\n", "r3 = RouteProblem('E', 'T', map=romania)\n", @@ -71,7 +75,7 @@ }, { "cell_type": "code", - "execution_count": 135, + "execution_count": 38, "id": "9e580734-b4f8-4d48-82d2-adcac10f8714", "metadata": {}, "outputs": [ @@ -79,18 +83,134 @@ "name": "stdout", "output_type": "stream", "text": [ + "['A', 'cost_limit_reached']\n", + "['A', 'cost_limit_reached']\n", + "['A', 'Z', 'cost_limit_reached']\n", + "['A', 'Z', 'cost_limit_reached']\n", + "['A', 'Z', 'O', 'cost_limit_reached']\n", + "['A', 'S', 'cost_limit_reached']\n", + "['A', 'T', 'cost_limit_reached']\n", + "['A', 'T', 'cost_limit_reached']\n", + "['A', 'S', 'cost_limit_reached']\n", + "['A', 'S', 'cost_limit_reached']\n", + "['A', 'S', 'cost_limit_reached']\n", + "['A', 'Z', 'O', 'cost_limit_reached']\n", + "['A', 'T', 'L', 'cost_limit_reached']\n", + "['A', 'S', 'R', 'cost_limit_reached']\n", + "['A', 'S', 'R', 'cost_limit_reached']\n", + "['A', 'S', 'F', 'cost_limit_reached']\n", + "['A', 'T', 'L', 'cost_limit_reached']\n", + "['A', 'S', 'R', 'cost_limit_reached']\n", + "['A', 'T', 'L', 'M', 'cost_limit_reached']\n", + "['A', 'T', 'L', 'M', 'cost_limit_reached']\n", + "['A', 'S', 'R', 'P', 'cost_limit_reached']\n", + "['A', 'S', 'R', 'P', 'cost_limit_reached']\n", + "['A', 'S', 'R', 'P', 'B']\n", "23\n", + "['N', 'I', 'cost_limit_reached']\n", + "['N', 'I', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'H', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'H', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'G', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'H', 'E', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'R', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'R', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'F', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'R', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'R', 'S', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'C', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'C', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'C', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'R', 'S', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'F', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'R', 'S', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'C', 'D', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'C', 'D', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'R', 'S', 'A', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'R', 'S', 'O', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'C', 'D', 'M', 'cost_limit_reached']\n", + "['N', 'I', 'V', 'U', 'B', 'P', 'C', 'D', 'M', 'L']\n", "35\n", - "37\n" + "['E', 'H', 'cost_limit_reached']\n", + "['E', 'H', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'V', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'G', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'V', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'V', 'I', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'V', 'I', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'R', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'R', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'F', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'V', 'I', 'N', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'R', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'R', 'S', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'C', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'C', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'C', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'R', 'S', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'F', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'R', 'S', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'C', 'D', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'C', 'D', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'R', 'S', 'A', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'R', 'S', 'O', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'C', 'D', 'M', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'C', 'D', 'M', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'R', 'S', 'A', 'cost_limit_reached']\n", + "['E', 'H', 'U', 'B', 'P', 'R', 'S', 'A', 'T']\n", + "37\n", + "['O', 'Z', 'cost_limit_reached']\n", + "['O', 'Z', 'cost_limit_reached']\n", + "['O', 'cost_limit_reached']\n", + "['O', 'Z', 'A', 'cost_limit_reached']\n", + "['O', 'S', 'cost_limit_reached']\n", + "['O', 'S', 'cost_limit_reached']\n", + "['O', 'Z', 'A', 'cost_limit_reached']\n", + "['O', 'Z', 'A', 'cost_limit_reached']\n", + "['O', 'S', 'cost_limit_reached']\n", + "['O', 'S', 'cost_limit_reached']\n", + "['O', 'S', 'R', 'cost_limit_reached']\n", + "['O', 'S', 'R', 'cost_limit_reached']\n", + "['O', 'S', 'F', 'cost_limit_reached']\n", + "['O', 'Z', 'A', 'T', 'cost_limit_reached']\n", + "['O', 'S', 'R', 'cost_limit_reached']\n", + "['O', 'Z', 'A', 'T', 'cost_limit_reached']\n", + "['O', 'S', 'R', 'P', 'cost_limit_reached']\n", + "['O', 'S', 'R', 'P', 'cost_limit_reached']\n", + "['O', 'Z', 'A', 'T', 'L', 'cost_limit_reached']\n", + "['O', 'Z', 'A', 'T', 'L', 'M']\n", + "20\n" ] }, { "data": { "text/plain": [ - "['E', 'H', 'U', 'B', 'P', 'R', 'S', 'A', 'T']" + "['O', 'Z', 'A', 'T', 'L', 'M']" ] }, - "execution_count": 135, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } @@ -98,7 +218,8 @@ "source": [ "path_states(iterative_lengthening_search(r1))\n", "path_states(iterative_lengthening_search(r2))\n", - "path_states(iterative_lengthening_search(r3))" + "path_states(iterative_lengthening_search(r3))\n", + "path_states(iterative_lengthening_search(r4))" ] } ], From 2ed977ea248c1332f296229bce28c32873b4cc3c Mon Sep 17 00:00:00 2001 From: hmp-anthony Date: Sat, 7 Sep 2024 16:57:42 +0100 Subject: [PATCH 23/42] added vac search --- iterative_lengthening_search.html | 139 +- vacuum_search_agent.ipynb | 82 + web_pages.html | 7573 +++++++++++++++++++++++++++++ web_pages.ipynb | 74 + web_pages.py | 7 + 5 files changed, 7866 insertions(+), 9 deletions(-) create mode 100644 vacuum_search_agent.ipynb create mode 100644 web_pages.html create mode 100644 web_pages.ipynb create mode 100644 web_pages.py diff --git a/iterative_lengthening_search.html b/iterative_lengthening_search.html index d9360d980..826971611 100644 --- a/iterative_lengthening_search.html +++ b/iterative_lengthening_search.html @@ -7514,11 +7514,15 @@