{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "b7420dde-12a4-411d-9d66-68699e1be86b", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "id": "d6945a68-6806-4635-ba3c-7cb1094b2e5d", "metadata": {}, "source": [ "# Drunken Ant" ] }, { "cell_type": "code", "execution_count": 26, "id": "049e94a5-ef9b-464a-b8fb-36120629db92", "metadata": {}, "outputs": [], "source": [ "class DrunkenAnt():\n", "\n", " # Constructor for the class\n", " def __init__(self, velocity):\n", " # Step size\n", " self.velocity = velocity\n", " # List to store the positions of the ant. Alternatively this could be a single 2-dim vector if we dont want to know the history\n", " self.trajectory = [np.zeros((2,))]\n", "\n", " # Calling the class directly returns the current position e.g. ant()\n", " def __call__(self,):\n", " # To traverse the list in reverse order we can use negative indices\n", " return self.trajectory[-1]\n", "\n", " # Perform n steps n=1 is used to prespecify a default value in case the user only wants to use ant.step() = ant.step(n=1)\n", " def steps(self, n=1):\n", " for _ in range(n):\n", " # Draw point between 0 to 1\n", " t = np.random.rand() \n", " # Map point to unit circle\n", " unit_vector = np.array([np.cos(2*np.pi*t), np.sin(2*np.pi*t)])\n", " # We multiply for random to add a little variability to the velocity (Min value is 0.2 and max value is 1)\n", " vel_noise = np.random.rand() * 0.8 + 0.2\n", " # Next post is just current position plus a random normal 2-dim vector times velocity\n", " next_pos = self.trajectory[-1] + (self.velocity * np.random.rand()) * unit_vector \n", " # Store the position\n", " self.trajectory.append(next_pos)\n", "\n", " # Plot the history\n", " def show_trajectory(self,):\n", " # 0 and 1 are the indices for the x and y coordinates, respectively\n", " x = np.array(self.trajectory)[:,0]\n", " y = np.array(self.trajectory)[:,1]\n", " # Draw a point at each step\n", " plt.scatter(x,y)\n", " # Connect the points with lines\n", " plt.plot(x,y)\n", " # Add some formatting to the graph\n", " plt.xlabel('X position')\n", " plt.ylabel('Y position')\n", " plt.xlabel('Drunken Ant Trajectory')\n", " # Add some labels to the points\n", " for i,(a,b) in enumerate(zip(x,y)):\n", " plt.text(a,b,f'{i}')" ] }, { "cell_type": "code", "execution_count": 27, "id": "6b192ac4-cbeb-4989-ac68-f55eb9f2fcfd", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Create an 'ant'\n", "ant = DrunkenAnt(0.5)\n", "# Take 10 steps \n", "ant.steps(n=10)\n", "# Visualize the trajectory\n", "ant.show_trajectory()" ] }, { "cell_type": "markdown", "id": "b20ae3fb-e07a-492b-b067-fe0b3843232e", "metadata": {}, "source": [ "# Path Search" ] }, { "cell_type": "markdown", "id": "b69804f6-8b8e-49ad-a65a-8f75dfe64223", "metadata": {}, "source": [ "Since we have to find all paths starting from each node the easiest way is to use recursive computing. \n", "\n", "Recursive computing consist on calling a function from within the same function. \n", "For a quick tutorial you can see: https://www.w3schools.com/python/gloss_python_function_recursion.asp\n", "\n", "The following code implements a simple recursive search, what we do is to start a new search for the goal node at each new node we visit. \n", "\n", "However we prevent new searches to start if we already visit the node at some point in the past; to achieve this goal every time we call the function we will pass a set with all the nodes we already visited at some point.\n", "\n", "Moreover, we also want to recover the path itself, thus we also need to node the current path that we traversed up to that point; to achieve this goal we will pass a list with the current path up to this point to the function.\n", "\n", "Effectively we will decompose the graph into a tree of paths (https://en.wikipedia.org/wiki/Tree_(graph_theory)) with the start index at the root and we will check every leaf node to see if it is the final index that we are looking for.\n", "\n", "Recursive computing may be a little confusing the first time you see it, but it is a powerful tool if learn to master it, since a lot of problems are considerably easier to understand with recursion." ] }, { "cell_type": "code", "execution_count": 102, "id": "18c7d460-b97a-4a4a-9f79-c247cd51fc0e", "metadata": {}, "outputs": [], "source": [ "def recursive_search(start_idx, final_idx, idx, visited_nodes, current_path, graph):\n", " # Check if we are done searching\n", " if idx == final_idx:\n", " # WE REACH THE FINAL NODE!\n", " # Return the path\n", " return [current_path + [idx]]\n", " else:\n", " # Get all neightbors of node\n", " neighbors = set(np.argwhere(graph[idx, :] == 1).reshape(-1))\n", " # Filter out the nodes already visited\n", " non_visited_neighbors = neighbors.difference(visited_nodes)\n", " # Check if the search can continue\n", " if len(non_visited_neighbors) == 0:\n", " # There are no more nodes to visit and we did not reach the final index\n", " # Return a void path\n", " return [None]\n", " else:\n", " # Create a list to store all the paths we have found\n", " paths = []\n", " # Visit each of the non visited neighbors recursively\n", " for neighbor in non_visited_neighbors:\n", " # Add the current index to the current path we are searching\n", " next_current_path = current_path + [idx]\n", " # Start a new search\n", " result = recursive_search(start_idx, final_idx, neighbor, visited_nodes.union(set([neighbor])), next_current_path, graph)\n", " # Since the algorithm is recursive this means we can obtain several paths \n", " for r in result:\n", " # Filter out all paths that failed to reach the node\n", " if r != None:\n", " paths.append( r )\n", " return paths" ] }, { "cell_type": "code", "execution_count": 108, "id": "02ee8582-7983-41a2-a31b-26ead67fb5fd", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[0, 1, 2, 3], [0, 1, 3], [0, 2, 1, 3], [0, 2, 3], [0, 3]]" ] }, "execution_count": 108, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a graph\n", "graph = np.array([\n", " [1, 1, 1, 1, 0],\n", " [0, 0, 1, 1, 0],\n", " [0, 1, 1, 1, 1],\n", " [1, 0, 0, 0, 0],\n", " [1, 0, 0, 0, 0]\n", "])\n", "# Select start and final nodes\n", "starting_node_idx = 0\n", "final_node_idx = 3\n", "# Run the search\n", "recursive_search(starting_node_idx, final_node_idx, starting_node_idx, set([starting_node_idx]), [], graph)" ] } ], "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.10.12" } }, "nbformat": 4, "nbformat_minor": 5 }