{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Search for AIMA 4th edition\n", "\n", "Implementation of search algorithms and search problems for AIMA.\n", "\n", "# Problems and Nodes\n", "\n", "We start by defining the abstract class for a `Problem`; specific problem domains will subclass this. To make it easier for algorithms that use a heuristic evaluation function, `Problem` has a default `h` function (uniformly zero), and subclasses can define their own default `h` function.\n", "\n", "We also define a `Node` in a search tree, and some functions on nodes: `expand` to generate successors; `path_actions` and `path_states` to recover aspects of the path from the node. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "import random\n", "import heapq\n", "import math\n", "import sys\n", "from collections import defaultdict, deque, Counter\n", "from itertools import combinations\n", "\n", "\n", "class Problem(object):\n", " \"\"\"The abstract class for a formal problem. A new domain subclasses this,\n", " overriding `actions` and `results`, and perhaps other methods.\n", " The default heuristic is 0 and the default action cost is 1 for all states.\n", " When yiou create an instance of a subclass, specify `initial`, and `goal` states \n", " (or give an `is_goal` method) and perhaps other keyword args for the subclass.\"\"\"\n", "\n", " def __init__(self, initial=None, goal=None, **kwds): \n", " self.__dict__.update(initial=initial, goal=goal, **kwds) \n", " \n", " def actions(self, state): raise NotImplementedError\n", " def result(self, state, action): raise NotImplementedError\n", " def is_goal(self, state): return state == self.goal\n", " def action_cost(self, s, a, s1): return 1\n", " def h(self, node): return 0\n", " \n", " def __str__(self):\n", " return '{}({!r}, {!r})'.format(\n", " type(self).__name__, self.initial, self.goal)\n", " \n", "\n", "class Node:\n", " \"A Node in a search tree.\"\n", " def __init__(self, state, parent=None, action=None, path_cost=0):\n", " self.__dict__.update(state=state, parent=parent, action=action, path_cost=path_cost)\n", "\n", " def __repr__(self): return '<{}>'.format(self.state)\n", " def __len__(self): return 0 if self.parent is None else (1 + len(self.parent))\n", " def __lt__(self, other): return self.path_cost < other.path_cost\n", " \n", " \n", "failure = Node('failure', path_cost=math.inf) # Indicates an algorithm couldn't find a solution.\n", "cutoff = Node('cutoff', path_cost=math.inf) # Indicates iterative deepening search was cut off.\n", " \n", " \n", "def expand(problem, node):\n", " \"Expand a node, generating the children nodes.\"\n", " s = node.state\n", " for action in problem.actions(s):\n", " s1 = problem.result(s, action)\n", " cost = node.path_cost + problem.action_cost(s, action, s1)\n", " yield Node(s1, node, action, cost)\n", " \n", "\n", "def path_actions(node):\n", " \"The sequence of actions to get to this node.\"\n", " if node.parent is None:\n", " return [] \n", " return path_actions(node.parent) + [node.action]\n", "\n", "\n", "def path_states(node):\n", " \"The sequence of states to get to this node.\"\n", " if node in (cutoff, failure, None): \n", " return []\n", " return path_states(node.parent) + [node.state]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Queues\n", "\n", "First-in-first-out and Last-in-first-out queues, and a `PriorityQueue`, which allows you to keep a collection of items, and continually remove from it the item with minimum `f(item)` score." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "FIFOQueue = deque\n", "\n", "LIFOQueue = list\n", "\n", "class PriorityQueue:\n", " \"\"\"A queue in which the item with minimum f(item) is always popped first.\"\"\"\n", "\n", " def __init__(self, items=(), key=lambda x: x): \n", " self.key = key\n", " self.items = [] # a heap of (score, item) pairs\n", " for item in items:\n", " self.add(item)\n", " \n", " def add(self, item):\n", " \"\"\"Add item to the queuez.\"\"\"\n", " pair = (self.key(item), item)\n", " heapq.heappush(self.items, pair)\n", "\n", " def pop(self):\n", " \"\"\"Pop and return the item with min f(item) value.\"\"\"\n", " return heapq.heappop(self.items)[1]\n", " \n", " def top(self): return self.items[0][1]\n", "\n", " def __len__(self): return len(self.items)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Search Algorithms: Best-First\n", "\n", "Best-first search with various *f(n)* functions gives us different search algorithms. Note that A\\*, weighted A\\* and greedy search can be given a heuristic function, `h`, but if `h` is not supplied they use the problem's default `h` function (if the problem does not define one, it is taken as *h(n)* = 0)." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def best_first_search(problem, f):\n", " \"Search nodes with minimum f(node) value first.\"\n", " node = Node(problem.initial)\n", " frontier = PriorityQueue([node], key=f)\n", " reached = {problem.initial: node}\n", " while frontier:\n", " node = frontier.pop()\n", " if problem.is_goal(node.state):\n", " return node\n", " for child in expand(problem, node):\n", " s = child.state\n", " if s not in reached or child.path_cost < reached[s].path_cost:\n", " reached[s] = child\n", " frontier.add(child)\n", " return failure\n", "\n", "\n", "def best_first_tree_search(problem, f):\n", " \"A version of best_first_search without the `reached` table.\"\n", " frontier = PriorityQueue([Node(problem.initial)], key=f)\n", " while frontier:\n", " node = frontier.pop()\n", " if problem.is_goal(node.state):\n", " return node\n", " for child in expand(problem, node):\n", " if not is_cycle(child):\n", " frontier.add(child)\n", " return failure\n", "\n", "\n", "def g(n): return n.path_cost\n", "\n", "\n", "def astar_search(problem, h=None):\n", " \"\"\"Search nodes with minimum f(n) = g(n) + h(n).\"\"\"\n", " h = h or problem.h\n", " return best_first_search(problem, f=lambda n: g(n) + h(n))\n", "\n", "\n", "def astar_tree_search(problem, h=None):\n", " \"\"\"Search nodes with minimum f(n) = g(n) + h(n), with no `reached` table.\"\"\"\n", " h = h or problem.h\n", " return best_first_tree_search(problem, f=lambda n: g(n) + h(n))\n", "\n", "\n", "def weighted_astar_search(problem, h=None, weight=1.4):\n", " \"\"\"Search nodes with minimum f(n) = g(n) + weight * h(n).\"\"\"\n", " h = h or problem.h\n", " return best_first_search(problem, f=lambda n: g(n) + weight * h(n))\n", "\n", " \n", "def greedy_bfs(problem, h=None):\n", " \"\"\"Search nodes with minimum h(n).\"\"\"\n", " h = h or problem.h\n", " return best_first_search(problem, f=h)\n", "\n", "\n", "def uniform_cost_search(problem):\n", " \"Search nodes with minimum path cost first.\"\n", " return best_first_search(problem, f=g)\n", "\n", "\n", "def breadth_first_bfs(problem):\n", " \"Search shallowest nodes in the search tree first; using best-first.\"\n", " return best_first_search(problem, f=len)\n", "\n", "\n", "def depth_first_bfs(problem):\n", " \"Search deepest nodes in the search tree first; using best-first.\"\n", " return best_first_search(problem, f=lambda n: -len(n))\n", "\n", "\n", "def is_cycle(node, k=30):\n", " \"Does this node form a cycle of length k or less?\"\n", " def find_cycle(ancestor, k):\n", " return (ancestor is not None and k > 0 and\n", " (ancestor.state == node.state or find_cycle(ancestor.parent, k - 1)))\n", " return find_cycle(node.parent, k)\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Other Search Algorithms\n", "\n", "Here are the other search algorithms:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def breadth_first_search(problem):\n", " \"Search shallowest nodes in the search tree first.\"\n", " node = Node(problem.initial)\n", " if problem.is_goal(problem.initial):\n", " return node\n", " frontier = FIFOQueue([node])\n", " reached = {problem.initial}\n", " while frontier:\n", " node = frontier.pop()\n", " for child in expand(problem, node):\n", " s = child.state\n", " if problem.is_goal(s):\n", " return child\n", " if s not in reached:\n", " reached.add(s)\n", " frontier.appendleft(child)\n", " return failure\n", "\n", "\n", "def iterative_deepening_search(problem):\n", " \"Do depth-limited search with increasing depth limits.\"\n", " for limit in range(1, sys.maxsize):\n", " result = depth_limited_search(problem, limit)\n", " if result != cutoff:\n", " return result\n", " \n", " \n", "def depth_limited_search(problem, limit=10):\n", " \"Search deepest nodes in the search tree first.\"\n", " frontier = LIFOQueue([Node(problem.initial)])\n", " result = failure\n", " while frontier:\n", " node = frontier.pop()\n", " if problem.is_goal(node.state):\n", " return node\n", " elif len(node) >= limit:\n", " result = cutoff\n", " elif not is_cycle(node):\n", " for child in expand(problem, node):\n", " frontier.append(child)\n", " return result\n", "\n", "\n", "def depth_first_recursive_search(problem, node=None):\n", " if node is None: \n", " node = Node(problem.initial)\n", " if problem.is_goal(node.state):\n", " return node\n", " elif is_cycle(node):\n", " return failure\n", " else:\n", " for child in expand(problem, node):\n", " result = depth_first_recursive_search(problem, child)\n", " if result:\n", " return result\n", " return failure" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'r2' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_1075091/2231190771.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mpath_states\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdepth_first_recursive_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mr2\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[0;31mNameError\u001b[0m: name 'r2' is not defined" ] } ], "source": [ "path_states(depth_first_recursive_search(r2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Bidirectional Best-First Search" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def bidirectional_best_first_search(problem_f, f_f, problem_b, f_b, terminated):\n", " node_f = Node(problem_f.initial)\n", " node_b = Node(problem_f.goal)\n", " frontier_f, reached_f = PriorityQueue([node_f], key=f_f), {node_f.state: node_f}\n", " frontier_b, reached_b = PriorityQueue([node_b], key=f_b), {node_b.state: node_b}\n", " solution = failure\n", " while frontier_f and frontier_b and not terminated(solution, frontier_f, frontier_b):\n", " def S1(node, f):\n", " return str(int(f(node))) + ' ' + str(path_states(node))\n", " print('Bi:', S1(frontier_f.top(), f_f), S1(frontier_b.top(), f_b))\n", " if f_f(frontier_f.top()) < f_b(frontier_b.top()):\n", " solution = proceed('f', problem_f, frontier_f, reached_f, reached_b, solution)\n", " else:\n", " solution = proceed('b', problem_b, frontier_b, reached_b, reached_f, solution)\n", " return solution\n", "\n", "def inverse_problem(problem):\n", " if isinstance(problem, CountCalls):\n", " return CountCalls(inverse_problem(problem._object))\n", " else:\n", " inv = copy.copy(problem)\n", " inv.initial, inv.goal = inv.goal, inv.initial\n", " return inv" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "def bidirectional_uniform_cost_search(problem_f):\n", " def terminated(solution, frontier_f, frontier_b):\n", " n_f, n_b = frontier_f.top(), frontier_b.top()\n", " return g(n_f) + g(n_b) > g(solution)\n", " return bidirectional_best_first_search(problem_f, g, inverse_problem(problem_f), g, terminated)\n", "\n", "def bidirectional_astar_search(problem_f):\n", " def terminated(solution, frontier_f, frontier_b):\n", " nf, nb = frontier_f.top(), frontier_b.top()\n", " return g(nf) + g(nb) > g(solution)\n", " problem_f = inverse_problem(problem_f)\n", " return bidirectional_best_first_search(problem_f, lambda n: g(n) + problem_f.h(n),\n", " problem_b, lambda n: g(n) + problem_b.h(n), \n", " terminated)\n", " \n", "\n", "def proceed(direction, problem, frontier, reached, reached2, solution):\n", " node = frontier.pop()\n", " for child in expand(problem, node):\n", " s = child.state\n", " print('proceed', direction, S(child))\n", " if s not in reached or child.path_cost < reached[s].path_cost:\n", " frontier.add(child)\n", " reached[s] = child\n", " if s in reached2: # Frontiers collide; solution found\n", " solution2 = (join_nodes(child, reached2[s]) if direction == 'f' else\n", " join_nodes(reached2[s], child))\n", " #print('solution', path_states(solution2), solution2.path_cost, \n", " # path_states(child), path_states(reached2[s]))\n", " if solution2.path_cost < solution.path_cost:\n", " solution = solution2\n", " return solution\n", "\n", "S = path_states\n", "\n", "#A-S-R + B-P-R => A-S-R-P + B-P\n", "def join_nodes(nf, nb):\n", " \"\"\"Join the reverse of the backward node nb to the forward node nf.\"\"\"\n", " #print('join', S(nf), S(nb))\n", " join = nf\n", " while nb.parent is not None:\n", " cost = join.path_cost + nb.path_cost - nb.parent.path_cost\n", " join = Node(nb.parent.state, join, nb.action, cost)\n", " nb = nb.parent\n", " #print(' now join', S(join), 'with nb', S(nb), 'parent', S(nb.parent))\n", " return join\n", " \n", " " ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "#A , B = uniform_cost_search(r1), uniform_cost_search(r2)\n", "#path_states(A), path_states(B)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "#path_states(append_nodes(A, B))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# TODO: RBFS" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Problem Domains\n", "\n", "Now we turn our attention to defining some problem domains as subclasses of `Problem`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Route Finding Problems\n", "\n", "![](romania.png)\n", "\n", "In a `RouteProblem`, the states are names of \"cities\" (or other locations), like `'A'` for Arad. The actions are also city names; `'Z'` is the action to move to city `'Z'`. The layout of cities is given by a separate data structure, a `Map`, which is a graph where there are vertexes (cities), links between vertexes, distances (costs) of those links (if not specified, the default is 1 for every link), and optionally the 2D (x, y) location of each city can be specified. A `RouteProblem` takes this `Map` as input and allows actions to move between linked cities. The default heuristic is straight-line distance to the goal, or is uniformly zero if locations were not given." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "class RouteProblem(Problem):\n", " \"\"\"A problem to find a route between locations on a `Map`.\n", " Create a problem with RouteProblem(start, goal, map=Map(...)}).\n", " States are the vertexes in the Map graph; actions are destination states.\"\"\"\n", " \n", " def actions(self, state): \n", " \"\"\"The places neighboring `state`.\"\"\"\n", " return self.map.neighbors[state]\n", " \n", " def result(self, state, action):\n", " \"\"\"Go to the `action` place, if the map says that is possible.\"\"\"\n", " return action if action in self.map.neighbors[state] else state\n", " \n", " def action_cost(self, s, action, s1):\n", " \"\"\"The distance (cost) to go from s to s1.\"\"\"\n", " return self.map.distances[s, s1]\n", " \n", " def h(self, node):\n", " \"Straight-line distance between state and the goal.\"\n", " locs = self.map.locations\n", " return straight_line_distance(locs[node.state], locs[self.goal])\n", " \n", " \n", "def straight_line_distance(A, B):\n", " \"Straight-line distance between two points.\"\n", " return sum(abs(a - b)**2 for (a, b) in zip(A, B)) ** 0.5" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "class Map:\n", " \"\"\"A map of places in a 2D world: a graph with vertexes and links between them. \n", " In `Map(links, locations)`, `links` can be either [(v1, v2)...] pairs, \n", " or a {(v1, v2): distance...} dict. Optional `locations` can be {v1: (x, y)} \n", " If `directed=False` then for every (v1, v2) link, we add a (v2, v1) link.\"\"\"\n", "\n", " def __init__(self, links, locations=None, directed=False):\n", " if not hasattr(links, 'items'): # Distances are 1 by default\n", " links = {link: 1 for link in links}\n", " if not directed:\n", " for (v1, v2) in list(links):\n", " links[v2, v1] = links[v1, v2]\n", " self.distances = links\n", " self.neighbors = multimap(links)\n", " self.locations = locations or defaultdict(lambda: (0, 0))\n", "\n", " \n", "def multimap(pairs) -> dict:\n", " \"Given (key, val) pairs, make a dict of {key: [val,...]}.\"\n", " result = defaultdict(list)\n", " for key, val in pairs:\n", " result[key].append(val)\n", " return result" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# Some specific RouteProblems\n", "\n", "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": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['A', 'S', 'R', 'P', 'B']" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "path_states(uniform_cost_search(r1)) # Lowest-cost path from Arab to Bucharest" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['A', 'S', 'F', 'B']" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "path_states(breadth_first_search(r1)) # Breadth-first: fewer steps, higher path cost" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Grid Problems\n", "\n", "A `GridProblem` involves navigating on a 2D grid, with some cells being impassible obstacles. By default you can move to any of the eight neighboring cells that are not obstacles (but in a problem instance you can supply a `directions=` keyword to change that). Again, the default heuristic is straight-line distance to the goal. States are `(x, y)` cell locations, such as `(4, 2)`, and actions are `(dx, dy)` cell movements, such as `(0, -1)`, which means leave the `x` coordinate alone, and decrement the `y` coordinate by 1." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "class GridProblem(Problem):\n", " \"\"\"Finding a path on a 2D grid with obstacles. Obstacles are (x, y) cells.\"\"\"\n", "\n", " def __init__(self, initial=(15, 30), goal=(130, 30), obstacles=(), **kwds):\n", " Problem.__init__(self, initial=initial, goal=goal, \n", " obstacles=set(obstacles) - {initial, goal}, **kwds)\n", "\n", " directions = [(-1, -1), (0, -1), (1, -1),\n", " (-1, 0), (1, 0),\n", " (-1, +1), (0, +1), (1, +1)]\n", " \n", " def action_cost(self, s, action, s1): return straight_line_distance(s, s1)\n", " \n", " def h(self, node): return straight_line_distance(node.state, self.goal)\n", " \n", " def result(self, state, action): \n", " \"Both states and actions are represented by (x, y) pairs.\"\n", " return action if action not in self.obstacles else state\n", " \n", " 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", " \n", "class ErraticVacuum(Problem):\n", " def actions(self, state): \n", " return ['suck', 'forward', 'backward']\n", " \n", " def results(self, state, action): return self.table[action][state]\n", " \n", " table = dict(suck= {1:{5,7}, 2:{4,8}, 3:{7}, 4:{2,4}, 5:{1,5}, 6:{8}, 7:{3,7}, 8:{6,8}},\n", " forward= {1:{2}, 2:{2}, 3:{4}, 4:{4}, 5:{6}, 6:{6}, 7:{8}, 8:{8}},\n", " backward={1:{1}, 2:{1}, 3:{3}, 4:{3}, 5:{5}, 6:{5}, 7:{7}, 8:{7}})" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "# Some grid routing problems\n", "\n", "# The following can be used to create obstacles:\n", " \n", "def random_lines(X=range(15, 130), Y=range(60), N=150, lengths=range(6, 12)):\n", " \"\"\"The set of cells in N random lines of the given lengths.\"\"\"\n", " result = set()\n", " for _ in range(N):\n", " x, y = random.choice(X), random.choice(Y)\n", " dx, dy = random.choice(((0, 1), (1, 0)))\n", " result |= line(x, y, dx, dy, random.choice(lengths))\n", " return result\n", "\n", "def line(x, y, dx, dy, length):\n", " \"\"\"A line of `length` cells starting at (x, y) and going in (dx, dy) direction.\"\"\"\n", " return {(x + i * dx, y + i * dy) for i in range(length)}\n", "\n", "random.seed(42) # To make this reproducible\n", "\n", "frame = line(-10, 20, 0, 1, 20) | line(150, 20, 0, 1, 20)\n", "cup = line(102, 44, -1, 0, 15) | line(102, 20, -1, 0, 20) | line(102, 44, 0, -1, 24)\n", "\n", "d1 = GridProblem(obstacles=random_lines(N=100) | frame)\n", "d2 = GridProblem(obstacles=random_lines(N=150) | frame)\n", "d3 = GridProblem(obstacles=random_lines(N=200) | frame)\n", "d4 = GridProblem(obstacles=random_lines(N=250) | frame)\n", "d5 = GridProblem(obstacles=random_lines(N=300) | frame)\n", "d6 = GridProblem(obstacles=cup | frame)\n", "d7 = GridProblem(obstacles=cup | frame | line(50, 35, 0, -1, 10) | line(60, 37, 0, -1, 17) | line(70, 31, 0, -1, 19))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 8 Puzzle Problems\n", "\n", "![](https://ece.uwaterloo.ca/~dwharder/aads/Algorithms/N_puzzles/images/puz3.png)\n", "\n", "A sliding tile puzzle where you can swap the blank with an adjacent piece, trying to reach a goal configuration. The cells are numbered 0 to 8, starting at the top left and going row by row left to right. The pieces are numebred 1 to 8, with 0 representing the blank. An action is the cell index number that is to be swapped with the blank (*not* the actual number to be swapped but the index into the state). So the diagram above left is the state `(5, 2, 7, 8, 4, 0, 1, 3, 6)`, and the action is `8`, because the cell number 8 (the 9th or last cell, the `6` in the bottom right) is swapped with the blank.\n", "\n", "There are two disjoint sets of states that cannot be reached from each other. One set has an even number of \"inversions\"; the other has an odd number. An inversion is when a piece in the state is larger than a piece that follows it.\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "class EightPuzzle(Problem):\n", " \"\"\" The problem of sliding tiles numbered from 1 to 8 on a 3x3 board,\n", " where one of the squares is a blank, trying to reach a goal configuration.\n", " A board state is represented as a tuple of length 9, where the element at index i \n", " represents the tile number at index i, or 0 if for the empty square, e.g. the goal:\n", " 1 2 3\n", " 4 5 6 ==> (1, 2, 3, 4, 5, 6, 7, 8, 0)\n", " 7 8 _\n", " \"\"\"\n", "\n", " def __init__(self, initial, goal=(0, 1, 2, 3, 4, 5, 6, 7, 8)):\n", " assert inversions(initial) % 2 == inversions(goal) % 2 # Parity check\n", " self.initial, self.goal = initial, goal\n", " \n", " def actions(self, state):\n", " \"\"\"The indexes of the squares that the blank can move to.\"\"\"\n", " moves = ((1, 3), (0, 2, 4), (1, 5),\n", " (0, 4, 6), (1, 3, 5, 7), (2, 4, 8),\n", " (3, 7), (4, 6, 8), (7, 5))\n", " blank = state.index(0)\n", " return moves[blank]\n", " \n", " def result(self, state, action):\n", " \"\"\"Swap the blank with the square numbered `action`.\"\"\"\n", " s = list(state)\n", " blank = state.index(0)\n", " s[action], s[blank] = s[blank], s[action]\n", " return tuple(s)\n", " \n", " def h1(self, node):\n", " \"\"\"The misplaced tiles heuristic.\"\"\"\n", " return hamming_distance(node.state, self.goal)\n", " \n", " def h2(self, node):\n", " \"\"\"The Manhattan heuristic.\"\"\"\n", " X = (0, 1, 2, 0, 1, 2, 0, 1, 2)\n", " Y = (0, 0, 0, 1, 1, 1, 2, 2, 2)\n", " return sum(abs(X[s] - X[g]) + abs(Y[s] - Y[g])\n", " for (s, g) in zip(node.state, self.goal) if s != 0)\n", " \n", " def h(self, node): return h2(self, node)\n", " \n", " \n", "def hamming_distance(A, B):\n", " \"Number of positions where vectors A and B are different.\"\n", " return sum(a != b for a, b in zip(A, B))\n", " \n", "\n", "def inversions(board):\n", " \"The number of times a piece is a smaller number than a following piece.\"\n", " return sum((a > b and a != 0 and b != 0) for (a, b) in combinations(board, 2))\n", " \n", " \n", "def board8(board, fmt=(3 * '{} {} {}\\n')):\n", " \"A string representing an 8-puzzle board\"\n", " return fmt.format(*board).replace('0', '_')\n", "\n", "class Board(defaultdict):\n", " empty = '.'\n", " off = '#'\n", " def __init__(self, board=None, width=8, height=8, to_move=None, **kwds):\n", " if board is not None:\n", " self.update(board)\n", " self.width, self.height = (board.width, board.height) \n", " else:\n", " self.width, self.height = (width, height)\n", " self.to_move = to_move\n", "\n", " def __missing__(self, key):\n", " x, y = key\n", " if x < 0 or x >= self.width or y < 0 or y >= self.height:\n", " return self.off\n", " else:\n", " return self.empty\n", " \n", " def __repr__(self):\n", " def row(y): return ' '.join(self[x, y] for x in range(self.width))\n", " return '\\n'.join(row(y) for y in range(self.height))\n", " \n", " def __hash__(self): \n", " return hash(tuple(sorted(self.items()))) + hash(self.to_move)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "# Some specific EightPuzzle problems\n", "\n", "e1 = EightPuzzle((1, 4, 2, 0, 7, 5, 3, 6, 8))\n", "e2 = EightPuzzle((1, 2, 3, 4, 5, 6, 7, 8, 0))\n", "e3 = EightPuzzle((4, 0, 2, 5, 1, 3, 7, 8, 6))\n", "e4 = EightPuzzle((7, 2, 4, 5, 0, 6, 8, 3, 1))\n", "e5 = EightPuzzle((8, 6, 7, 2, 5, 4, 3, 0, 1))" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'h2' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_1075091/1214029143.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Solve an 8 puzzle problem and print out each state\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0ms\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mpath_states\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mastar_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me1\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 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mboard8\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ms\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/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36mastar_search\u001b[0;34m(problem, h)\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;34m\"\"\"Search nodes with minimum f(n) = g(n) + h(n).\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mh\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 37\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mbest_first_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\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[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36mbest_first_search\u001b[0;34m(problem, f)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"Search nodes with minimum f(node) value first.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mnode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mNode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minitial\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mfrontier\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPriorityQueue\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnode\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mf\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 5\u001b[0m \u001b[0mreached\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minitial\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mnode\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;32mwhile\u001b[0m \u001b[0mfrontier\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/2092060460.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, items, key)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# a heap of (score, item) pairs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mitem\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mitems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\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 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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/tmp/ipykernel_1075091/2092060460.py\u001b[0m in \u001b[0;36madd\u001b[0;34m(self, item)\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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 15\u001b[0m \u001b[0;34m\"\"\"Add item to the queuez.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m \u001b[0mpair\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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 17\u001b[0m \u001b[0mheapq\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mheappush\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpair\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36m\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;34m\"\"\"Search nodes with minimum f(n) = g(n) + h(n).\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mh\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 37\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mbest_first_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\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[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/1915594217.py\u001b[0m in \u001b[0;36mh\u001b[0;34m(self, node)\u001b[0m\n\u001b[1;32m 39\u001b[0m for (s, g) in zip(node.state, self.goal) if s != 0)\n\u001b[1;32m 40\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 41\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mh2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnode\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 42\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 43\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mNameError\u001b[0m: name 'h2' is not defined" ] } ], "source": [ "# Solve an 8 puzzle problem and print out each state\n", "\n", "for s in path_states(astar_search(e1)):\n", " print(board8(s))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Water Pouring Problems\n", "\n", "![](http://puzzles.nigelcoldwell.co.uk/images/water22.png)\n", "\n", "In a [water pouring problem](https://en.wikipedia.org/wiki/Water_pouring_puzzle) you are given a collection of jugs, each of which has a size (capacity) in, say, litres, and a current level of water (in litres). The goal is to measure out a certain level of water; it can appear in any of the jugs. For example, in the movie *Die Hard 3*, the heroes were faced with the task of making exactly 4 gallons from jugs of size 5 gallons and 3 gallons.) A state is represented by a tuple of current water levels, and the available actions are:\n", "- `(Fill, i)`: fill the `i`th jug all the way to the top (from a tap with unlimited water).\n", "- `(Dump, i)`: dump all the water out of the `i`th jug.\n", "- `(Pour, i, j)`: pour water from the `i`th jug into the `j`th jug until either the jug `i` is empty, or jug `j` is full, whichever comes first." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "class PourProblem(Problem):\n", " \"\"\"Problem about pouring water between jugs to achieve some water level.\n", " Each state is a tuples of water levels. In the initialization, also provide a tuple of \n", " jug sizes, e.g. PourProblem(initial=(0, 0), goal=4, sizes=(5, 3)), \n", " which means two jugs of sizes 5 and 3, initially both empty, with the goal\n", " of getting a level of 4 in either jug.\"\"\"\n", " \n", " def actions(self, state):\n", " \"\"\"The actions executable in this state.\"\"\"\n", " jugs = range(len(state))\n", " return ([('Fill', i) for i in jugs if state[i] < self.sizes[i]] +\n", " [('Dump', i) for i in jugs if state[i]] +\n", " [('Pour', i, j) for i in jugs if state[i] for j in jugs if i != j])\n", "\n", " def result(self, state, action):\n", " \"\"\"The state that results from executing this action in this state.\"\"\"\n", " result = list(state)\n", " act, i, *_ = action\n", " if act == 'Fill': # Fill i to capacity\n", " result[i] = self.sizes[i]\n", " elif act == 'Dump': # Empty i\n", " result[i] = 0\n", " elif act == 'Pour': # Pour from i into j\n", " j = action[2]\n", " amount = min(state[i], self.sizes[j] - state[j])\n", " result[i] -= amount\n", " result[j] += amount\n", " return tuple(result)\n", "\n", " def is_goal(self, state):\n", " \"\"\"True if the goal level is in any one of the jugs.\"\"\"\n", " return self.goal in state" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In a `GreenPourProblem`, the states and actions are the same, but instead of all actions costing 1, in these problems the cost of an action is the amount of water that flows from the tap. (There is an issue that non-*Fill* actions have 0 cost, which in general can lead to indefinitely long solutions, but in this problem there is a finite number of states, so we're ok.)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "class GreenPourProblem(PourProblem): \n", " \"\"\"A PourProblem in which the cost is the amount of water used.\"\"\"\n", " def action_cost(self, s, action, s1):\n", " \"The cost is the amount of water used.\"\n", " act, i, *_ = action\n", " return self.sizes[i] - s[i] if act == 'Fill' else 0" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "# Some specific PourProblems\n", "\n", "p1 = PourProblem((1, 1, 1), 13, sizes=(2, 16, 32))\n", "p2 = PourProblem((0, 0, 0), 21, sizes=(8, 11, 31))\n", "p3 = PourProblem((0, 0), 8, sizes=(7,9))\n", "p4 = PourProblem((0, 0, 0), 21, sizes=(8, 11, 31))\n", "p5 = PourProblem((0, 0), 4, sizes=(3, 5))\n", "\n", "g1 = GreenPourProblem((1, 1, 1), 13, sizes=(2, 16, 32))\n", "g2 = GreenPourProblem((0, 0, 0), 21, sizes=(8, 11, 31))\n", "g3 = GreenPourProblem((0, 0), 8, sizes=(7,9))\n", "g4 = GreenPourProblem((0, 0, 0), 21, sizes=(8, 11, 31))\n", "g5 = GreenPourProblem((0, 0), 4, sizes=(3, 5))" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "([('Fill', 1), ('Pour', 1, 0), ('Dump', 0), ('Pour', 1, 0)],\n", " [(1, 1, 1), (1, 16, 1), (2, 15, 1), (0, 15, 1), (2, 13, 1)])" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Solve the PourProblem of getting 13 in some jug, and show the actions and states\n", "soln = breadth_first_search(p1)\n", "path_actions(soln), path_states(soln)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Pancake Sorting Problems\n", "\n", "Given a stack of pancakes of various sizes, can you sort them into a stack of decreasing sizes, largest on bottom to smallest on top? You have a spatula with which you can flip the top `i` pancakes. This is shown below for `i = 3`; on the top the spatula grabs the first three pancakes; on the bottom we see them flipped:\n", "\n", "\n", "![](https://upload.wikimedia.org/wikipedia/commons/0/0f/Pancake_sort_operation.png)\n", "\n", "How many flips will it take to get the whole stack sorted? This is an interesting [problem](https://en.wikipedia.org/wiki/Pancake_sorting) that Bill Gates has [written about](https://people.eecs.berkeley.edu/~christos/papers/Bounds%20For%20Sorting%20By%20Prefix%20Reversal.pdf). A reasonable heuristic for this problem is the *gap heuristic*: if we look at neighboring pancakes, if, say, the 2nd smallest is next to the 3rd smallest, that's good; they should stay next to each other. But if the 2nd smallest is next to the 4th smallest, that's bad: we will require at least one move to separate them and insert the 3rd smallest between them. The gap heuristic counts the number of neighbors that have a gap like this. In our specification of the problem, pancakes are ranked by size: the smallest is `1`, the 2nd smallest `2`, and so on, and the representation of a state is a tuple of these rankings, from the top to the bottom pancake. Thus the goal state is always `(1, 2, ..., `*n*`)` and the initial (top) state in the diagram above is `(2, 1, 4, 6, 3, 5)`.\n" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "class PancakeProblem(Problem):\n", " \"\"\"A PancakeProblem the goal is always `tuple(range(1, n+1))`, where the\n", " initial state is a permutation of `range(1, n+1)`. An act is the index `i` \n", " of the top `i` pancakes that will be flipped.\"\"\"\n", " \n", " def __init__(self, initial): \n", " self.initial, self.goal = tuple(initial), tuple(sorted(initial))\n", " \n", " def actions(self, state): return range(2, len(state) + 1)\n", "\n", " def result(self, state, i): return state[:i][::-1] + state[i:]\n", " \n", " def h(self, node):\n", " \"The gap heuristic.\"\n", " s = node.state\n", " return sum(abs(s[i] - s[i - 1]) > 1 for i in range(1, len(s)))" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "c0 = PancakeProblem((2, 1, 4, 6, 3, 5))\n", "c1 = PancakeProblem((4, 6, 2, 5, 1, 3))\n", "c2 = PancakeProblem((1, 3, 7, 5, 2, 6, 4))\n", "c3 = PancakeProblem((1, 7, 2, 6, 3, 5, 4))\n", "c4 = PancakeProblem((1, 3, 5, 7, 9, 2, 4, 6, 8))" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[(2, 1, 4, 6, 3, 5),\n", " (6, 4, 1, 2, 3, 5),\n", " (5, 3, 2, 1, 4, 6),\n", " (4, 1, 2, 3, 5, 6),\n", " (3, 2, 1, 4, 5, 6),\n", " (1, 2, 3, 4, 5, 6)]" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Solve a pancake problem\n", "path_states(astar_search(c0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Jumping Frogs Puzzle\n", "\n", "In this puzzle (which also can be played as a two-player game), the initial state is a line of squares, with N pieces of one kind on the left, then one empty square, then N pieces of another kind on the right. The diagram below uses 2 blue toads and 2 red frogs; we will represent this as the string `'LL.RR'`. The goal is to swap the pieces, arriving at `'RR.LL'`. An `'L'` piece moves left-to-right, either sliding one space ahead to an empty space, or two spaces ahead if that space is empty and if there is an `'R'` in between to hop over. The `'R'` pieces move right-to-left analogously. An action will be an `(i, j)` pair meaning to swap the pieces at those indexes. The set of actions for the N = 2 position below is `{(1, 2), (3, 2)}`, meaning either the blue toad in position 1 or the red frog in position 3 can swap places with the blank in position 2.\n", "\n", "![](https://upload.wikimedia.org/wikipedia/commons/2/2f/ToadsAndFrogs.png)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "class JumpingPuzzle(Problem):\n", " \"\"\"Try to exchange L and R by moving one ahead or hopping two ahead.\"\"\"\n", " def __init__(self, N=2):\n", " self.initial = N*'L' + '.' + N*'R'\n", " self.goal = self.initial[::-1]\n", " \n", " def actions(self, state):\n", " \"\"\"Find all possible move or hop moves.\"\"\"\n", " idxs = range(len(state))\n", " return ({(i, i + 1) for i in idxs if state[i:i+2] == 'L.'} # Slide\n", " |{(i, i + 2) for i in idxs if state[i:i+3] == 'LR.'} # Hop\n", " |{(i + 1, i) for i in idxs if state[i:i+2] == '.R'} # Slide\n", " |{(i + 2, i) for i in idxs if state[i:i+3] == '.LR'}) # Hop\n", "\n", " def result(self, state, action):\n", " \"\"\"An action (i, j) means swap the pieces at positions i and j.\"\"\"\n", " i, j = action\n", " result = list(state)\n", " result[i], result[j] = state[j], state[i]\n", " return ''.join(result)\n", " \n", " def h(self, node): return hamming_distance(node.state, self.goal)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(1, 2), (3, 2)}" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "JumpingPuzzle(N=2).actions('LL.RR')" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['LLL.RRR',\n", " 'LLLR.RR',\n", " 'LL.RLRR',\n", " 'L.LRLRR',\n", " 'LRL.LRR',\n", " 'LRLRL.R',\n", " 'LRLRLR.',\n", " 'LRLR.RL',\n", " 'LR.RLRL',\n", " '.RLRLRL',\n", " 'R.LRLRL',\n", " 'RRL.LRL',\n", " 'RRLRL.L',\n", " 'RRLR.LL',\n", " 'RR.RLLL',\n", " 'RRR.LLL']" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "j3 = JumpingPuzzle(N=3)\n", "j9 = JumpingPuzzle(N=9)\n", "path_states(astar_search(j3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Reporting Summary Statistics on Search Algorithms\n", "\n", "Now let's gather some metrics on how well each algorithm does. We'll use `CountCalls` to wrap a `Problem` object in such a way that calls to its methods are delegated to the original problem, but each call increments a counter. Once we've solved the problem, we print out summary statistics." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "class CountCalls:\n", " \"\"\"Delegate all attribute gets to the object, and count them in ._counts\"\"\"\n", " def __init__(self, obj):\n", " self._object = obj\n", " self._counts = Counter()\n", " \n", " def __getattr__(self, attr):\n", " \"Delegate to the original object, after incrementing a counter.\"\n", " self._counts[attr] += 1\n", " return getattr(self._object, attr)\n", "\n", " \n", "def report(searchers, problems, verbose=True):\n", " \"\"\"Show summary statistics for each searcher (and on each problem unless verbose is false).\"\"\"\n", " for searcher in searchers:\n", " print(searcher.__name__ + ':')\n", " total_counts = Counter()\n", " for p in problems:\n", " prob = CountCalls(p)\n", " soln = searcher(prob)\n", " counts = prob._counts; \n", " counts.update(actions=len(soln), cost=soln.path_cost)\n", " total_counts += counts\n", " if verbose: report_counts(counts, str(p)[:40])\n", " report_counts(total_counts, 'TOTAL\\n')\n", " \n", "def report_counts(counts, name):\n", " \"\"\"Print one line of the counts report.\"\"\"\n", " print('{:9,d} nodes |{:9,d} goal |{:5.0f} cost |{:8,d} actions | {}'.format(\n", " counts['result'], counts['is_goal'], counts['cost'], counts['actions'], name))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here's a tiny report for uniform-cost search on the jug pouring problems:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "uniform_cost_search:\n", " 948 nodes | 109 goal | 4 cost | 112 actions | PourProblem((1, 1, 1), 13)\n", " 3,499 nodes | 389 goal | 9 cost | 397 actions | PourProblem((0, 0, 0), 21)\n", " 124 nodes | 30 goal | 14 cost | 43 actions | PourProblem((0, 0), 8)\n", " 3,499 nodes | 389 goal | 9 cost | 397 actions | PourProblem((0, 0, 0), 21)\n", " 52 nodes | 14 goal | 6 cost | 19 actions | PourProblem((0, 0), 4)\n", " 8,122 nodes | 931 goal | 42 cost | 968 actions | TOTAL\n", "\n" ] } ], "source": [ "report([uniform_cost_search], [p1, p2, p3, p4, p5])" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "uniform_cost_search:\n", " 948 nodes | 109 goal | 4 cost | 112 actions | PourProblem((1, 1, 1), 13)\n", " 1,696 nodes | 190 goal | 10 cost | 204 actions | GreenPourProblem((1, 1, 1), 13)\n", " 3,499 nodes | 389 goal | 9 cost | 397 actions | PourProblem((0, 0, 0), 21)\n", " 4,072 nodes | 454 goal | 21 cost | 463 actions | GreenPourProblem((0, 0, 0), 21)\n", " 124 nodes | 30 goal | 14 cost | 43 actions | PourProblem((0, 0), 8)\n", " 124 nodes | 30 goal | 35 cost | 45 actions | GreenPourProblem((0, 0), 8)\n", " 3,499 nodes | 389 goal | 9 cost | 397 actions | PourProblem((0, 0, 0), 21)\n", " 4,072 nodes | 454 goal | 21 cost | 463 actions | GreenPourProblem((0, 0, 0), 21)\n", " 3,499 nodes | 389 goal | 9 cost | 397 actions | PourProblem((0, 0, 0), 21)\n", " 4,072 nodes | 454 goal | 21 cost | 463 actions | GreenPourProblem((0, 0, 0), 21)\n", " 3,590 nodes | 719 goal | 7 cost | 725 actions | PancakeProblem((4, 6, 2, 5, 1, 3), (1, 2\n", " 30,204 nodes | 5,035 goal | 8 cost | 5,042 actions | PancakeProblem((1, 3, 7, 5, 2, 6, 4), (1\n", " 22,068 nodes | 3,679 goal | 6 cost | 3,684 actions | PancakeProblem((1, 7, 2, 6, 3, 5, 4), (1\n", " 81,467 nodes | 12,321 goal | 174 cost | 12,435 actions | TOTAL\n", "\n", "breadth_first_search:\n", " 596 nodes | 597 goal | 4 cost | 73 actions | PourProblem((1, 1, 1), 13)\n", " 596 nodes | 597 goal | 15 cost | 73 actions | GreenPourProblem((1, 1, 1), 13)\n", " 2,618 nodes | 2,619 goal | 9 cost | 302 actions | PourProblem((0, 0, 0), 21)\n", " 2,618 nodes | 2,619 goal | 32 cost | 302 actions | GreenPourProblem((0, 0, 0), 21)\n", " 120 nodes | 121 goal | 14 cost | 42 actions | PourProblem((0, 0), 8)\n", " 120 nodes | 121 goal | 36 cost | 42 actions | GreenPourProblem((0, 0), 8)\n", " 2,618 nodes | 2,619 goal | 9 cost | 302 actions | PourProblem((0, 0, 0), 21)\n", " 2,618 nodes | 2,619 goal | 32 cost | 302 actions | GreenPourProblem((0, 0, 0), 21)\n", " 2,618 nodes | 2,619 goal | 9 cost | 302 actions | PourProblem((0, 0, 0), 21)\n", " 2,618 nodes | 2,619 goal | 32 cost | 302 actions | GreenPourProblem((0, 0, 0), 21)\n", " 2,951 nodes | 2,952 goal | 7 cost | 598 actions | PancakeProblem((4, 6, 2, 5, 1, 3), (1, 2\n", " 25,945 nodes | 25,946 goal | 8 cost | 4,333 actions | PancakeProblem((1, 3, 7, 5, 2, 6, 4), (1\n", " 5,975 nodes | 5,976 goal | 6 cost | 1,002 actions | PancakeProblem((1, 7, 2, 6, 3, 5, 4), (1\n", " 52,011 nodes | 52,024 goal | 213 cost | 7,975 actions | TOTAL\n", "\n" ] } ], "source": [ "report((uniform_cost_search, breadth_first_search), \n", " (p1, g1, p2, g2, p3, g3, p4, g4, p4, g4, c1, c2, c3)) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Comparing heuristics\n", "\n", "First, let's look at the eight puzzle problems, and compare three different heuristics the Manhattan heuristic, the less informative misplaced tiles heuristic, and the uninformed (i.e. *h* = 0) breadth-first search:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "breadth_first_search:\n", " 81 nodes | 82 goal | 5 cost | 35 actions | EightPuzzle((1, 4, 2, 0, 7, 5, 3, 6, 8),\n", " 160,948 nodes | 160,949 goal | 22 cost | 59,960 actions | EightPuzzle((1, 2, 3, 4, 5, 6, 7, 8, 0),\n", " 218,263 nodes | 218,264 goal | 23 cost | 81,829 actions | EightPuzzle((4, 0, 2, 5, 1, 3, 7, 8, 6),\n", " 418,771 nodes | 418,772 goal | 26 cost | 156,533 actions | EightPuzzle((7, 2, 4, 5, 0, 6, 8, 3, 1),\n", " 448,667 nodes | 448,668 goal | 27 cost | 167,799 actions | EightPuzzle((8, 6, 7, 2, 5, 4, 3, 0, 1),\n", "1,246,730 nodes |1,246,735 goal | 103 cost | 466,156 actions | TOTAL\n", "\n", "astar_misplaced_tiles:\n", " 17 nodes | 7 goal | 5 cost | 11 actions | EightPuzzle((1, 4, 2, 0, 7, 5, 3, 6, 8),\n", " 23,407 nodes | 8,726 goal | 22 cost | 8,747 actions | EightPuzzle((1, 2, 3, 4, 5, 6, 7, 8, 0),\n", " 38,632 nodes | 14,433 goal | 23 cost | 14,455 actions | EightPuzzle((4, 0, 2, 5, 1, 3, 7, 8, 6),\n", " 124,324 nodes | 46,553 goal | 26 cost | 46,578 actions | EightPuzzle((7, 2, 4, 5, 0, 6, 8, 3, 1),\n", " 156,111 nodes | 58,475 goal | 27 cost | 58,501 actions | EightPuzzle((8, 6, 7, 2, 5, 4, 3, 0, 1),\n", " 342,491 nodes | 128,194 goal | 103 cost | 128,292 actions | TOTAL\n", "\n", "astar_search:\n" ] }, { "ename": "NameError", "evalue": "name 'h2' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_1075091/1501421569.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mastar_misplaced_tiles\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mastar_search\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[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m report([breadth_first_search, astar_misplaced_tiles, astar_search], \n\u001b[0m\u001b[1;32m 4\u001b[0m [e1, e2, e3, e4, e5])\n", "\u001b[0;32m/tmp/ipykernel_1075091/1959091182.py\u001b[0m in \u001b[0;36mreport\u001b[0;34m(searchers, problems, verbose)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mp\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mproblems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0mprob\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCountCalls\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0msoln\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msearcher\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprob\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 21\u001b[0m \u001b[0mcounts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mprob\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_counts\u001b[0m\u001b[0;34m;\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0mcounts\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mactions\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msoln\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcost\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msoln\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath_cost\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36mastar_search\u001b[0;34m(problem, h)\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;34m\"\"\"Search nodes with minimum f(n) = g(n) + h(n).\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mh\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 37\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mbest_first_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\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[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36mbest_first_search\u001b[0;34m(problem, f)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"Search nodes with minimum f(node) value first.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mnode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mNode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minitial\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mfrontier\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPriorityQueue\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnode\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mf\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 5\u001b[0m \u001b[0mreached\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minitial\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mnode\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;32mwhile\u001b[0m \u001b[0mfrontier\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/2092060460.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, items, key)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# a heap of (score, item) pairs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mitem\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mitems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\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 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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/tmp/ipykernel_1075091/2092060460.py\u001b[0m in \u001b[0;36madd\u001b[0;34m(self, item)\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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 15\u001b[0m \u001b[0;34m\"\"\"Add item to the queuez.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m \u001b[0mpair\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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 17\u001b[0m \u001b[0mheapq\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mheappush\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpair\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36m\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;34m\"\"\"Search nodes with minimum f(n) = g(n) + h(n).\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mh\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 37\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mbest_first_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\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[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/1915594217.py\u001b[0m in \u001b[0;36mh\u001b[0;34m(self, node)\u001b[0m\n\u001b[1;32m 39\u001b[0m for (s, g) in zip(node.state, self.goal) if s != 0)\n\u001b[1;32m 40\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 41\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mh2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnode\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 42\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 43\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mNameError\u001b[0m: name 'h2' is not defined" ] } ], "source": [ "def astar_misplaced_tiles(problem): return astar_search(problem, h=problem.h1)\n", "\n", "report([breadth_first_search, astar_misplaced_tiles, astar_search], \n", " [e1, e2, e3, e4, e5])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see that all three algorithms get cost-optimal solutions, but the better the heuristic, the fewer nodes explored. \n", "Compared to the uninformed search, the misplaced tiles heuristic explores about 1/4 the number of nodes, and the Manhattan heuristic needs just 2%.\n", "\n", "Next, we can show the value of the gap heuristic for pancake sorting problems:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "report([astar_search, uniform_cost_search], [c1, c2, c3, c4])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We need to explore 300 times more nodes without the heuristic.\n", "\n", "# Comparing graph search and tree search\n", "\n", "Keeping the *reached* table in `best_first_search` allows us to do a graph search, where we notice when we reach a state by two different paths, rather than a tree search, where we have duplicated effort. The *reached* table consumes space and also saves time. How much time? In part it depends on how good the heuristics are at focusing the search. Below we show that on some pancake and eight puzzle problems, the tree search expands roughly twice as many nodes (and thus takes roughly twice as much time):" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "astar_search:\n" ] }, { "ename": "NameError", "evalue": "name 'h2' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_1075091/1052081939.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mreport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mastar_search\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mastar_tree_search\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0me1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0me2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0me3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0me4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr4\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[0;32m/tmp/ipykernel_1075091/1959091182.py\u001b[0m in \u001b[0;36mreport\u001b[0;34m(searchers, problems, verbose)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mp\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mproblems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0mprob\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCountCalls\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0msoln\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msearcher\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprob\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 21\u001b[0m \u001b[0mcounts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mprob\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_counts\u001b[0m\u001b[0;34m;\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0mcounts\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mactions\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msoln\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcost\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msoln\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath_cost\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36mastar_search\u001b[0;34m(problem, h)\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;34m\"\"\"Search nodes with minimum f(n) = g(n) + h(n).\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mh\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 37\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mbest_first_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\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[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36mbest_first_search\u001b[0;34m(problem, f)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"Search nodes with minimum f(node) value first.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mnode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mNode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minitial\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mfrontier\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPriorityQueue\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnode\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mf\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 5\u001b[0m \u001b[0mreached\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minitial\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mnode\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;32mwhile\u001b[0m \u001b[0mfrontier\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/2092060460.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, items, key)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# a heap of (score, item) pairs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mitem\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mitems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\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 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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/tmp/ipykernel_1075091/2092060460.py\u001b[0m in \u001b[0;36madd\u001b[0;34m(self, item)\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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 15\u001b[0m \u001b[0;34m\"\"\"Add item to the queuez.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m \u001b[0mpair\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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 17\u001b[0m \u001b[0mheapq\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mheappush\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpair\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36m\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;34m\"\"\"Search nodes with minimum f(n) = g(n) + h(n).\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mh\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 37\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mbest_first_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\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[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/1915594217.py\u001b[0m in \u001b[0;36mh\u001b[0;34m(self, node)\u001b[0m\n\u001b[1;32m 39\u001b[0m for (s, g) in zip(node.state, self.goal) if s != 0)\n\u001b[1;32m 40\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 41\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mh2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnode\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 42\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 43\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mNameError\u001b[0m: name 'h2' is not defined" ] } ], "source": [ "report([astar_search, astar_tree_search], [e1, e2, e3, e4, r1, r2, r3, r4])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Comparing different weighted search values\n", "\n", "Below we report on problems using these four algorithms:\n", "\n", "|Algorithm|*f*|Optimality|\n", "|:---------|---:|:----------:|\n", "|Greedy best-first search | *f = h*|nonoptimal|\n", "|Extra weighted A* search | *f = g + 2 × h*|nonoptimal|\n", "|Weighted A* search | *f = g + 1.4 × h*|nonoptimal|\n", "|A* search | *f = g + h*|optimal|\n", "|Uniform-cost search | *f = g*|optimal|\n", "\n", "We will see that greedy best-first search (which ranks nodes solely by the heuristic) explores the fewest number of nodes, but has the highest path costs. Weighted A* search explores twice as many nodes (on this problem set) but gets 10% better path costs. A* is optimal, but explores more nodes, and uniform-cost is also optimal, but explores an order of magnitude more nodes." ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "greedy_bfs:\n", " 0 nodes | 1 goal | 0 cost | 0 actions | RouteProblem('A', 'A')\n", " 9 nodes | 4 goal | 450 cost | 6 actions | RouteProblem('A', 'B')\n", " 28 nodes | 12 goal | 1207 cost | 22 actions | RouteProblem('N', 'L')\n", " 19 nodes | 8 goal | 837 cost | 14 actions | RouteProblem('E', 'T')\n", " 14 nodes | 6 goal | 572 cost | 10 actions | RouteProblem('O', 'M')\n" ] }, { "ename": "NameError", "evalue": "name 'h2' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_1075091/3931949981.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mextra_weighted_astar_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mweighted_astar_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mweight\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[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m report((greedy_bfs, extra_weighted_astar_search, weighted_astar_search, astar_search, uniform_cost_search), \n\u001b[0m\u001b[1;32m 4\u001b[0m (r0, r1, r2, r3, r4, e1, d1, d2, j9, e2, d3, d4, d6, d7, e3, e4))\n", "\u001b[0;32m/tmp/ipykernel_1075091/1959091182.py\u001b[0m in \u001b[0;36mreport\u001b[0;34m(searchers, problems, verbose)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mp\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mproblems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0mprob\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCountCalls\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0msoln\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msearcher\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprob\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 21\u001b[0m \u001b[0mcounts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mprob\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_counts\u001b[0m\u001b[0;34m;\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0mcounts\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mactions\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msoln\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcost\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msoln\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath_cost\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36mgreedy_bfs\u001b[0;34m(problem, h)\u001b[0m\n\u001b[1;32m 53\u001b[0m \u001b[0;34m\"\"\"Search nodes with minimum h(n).\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 54\u001b[0m \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mh\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 55\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mbest_first_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mh\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 56\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 57\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36mbest_first_search\u001b[0;34m(problem, f)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"Search nodes with minimum f(node) value first.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mnode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mNode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minitial\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mfrontier\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPriorityQueue\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnode\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mf\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 5\u001b[0m \u001b[0mreached\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minitial\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mnode\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;32mwhile\u001b[0m \u001b[0mfrontier\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/2092060460.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, items, key)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# a heap of (score, item) pairs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mitem\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mitems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\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 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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/tmp/ipykernel_1075091/2092060460.py\u001b[0m in \u001b[0;36madd\u001b[0;34m(self, item)\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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 15\u001b[0m \u001b[0;34m\"\"\"Add item to the queuez.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m \u001b[0mpair\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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 17\u001b[0m \u001b[0mheapq\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mheappush\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpair\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/1915594217.py\u001b[0m in \u001b[0;36mh\u001b[0;34m(self, node)\u001b[0m\n\u001b[1;32m 39\u001b[0m for (s, g) in zip(node.state, self.goal) if s != 0)\n\u001b[1;32m 40\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 41\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mh2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnode\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 42\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 43\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mNameError\u001b[0m: name 'h2' is not defined" ] } ], "source": [ "def extra_weighted_astar_search(problem): return weighted_astar_search(problem, weight=2)\n", " \n", "report((greedy_bfs, extra_weighted_astar_search, weighted_astar_search, astar_search, uniform_cost_search), \n", " (r0, r1, r2, r3, r4, e1, d1, d2, j9, e2, d3, d4, d6, d7, e3, e4))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see that greedy search expands the fewest nodes, but has the highest path costs. In contrast, A\\* gets optimal path costs, but expands 4 or 5 times more nodes. Weighted A* is a good compromise, using half the compute time as A\\*, and achieving path costs within 1% or 2% of optimal. Uniform-cost is optimal, but is an order of magnitude slower than A\\*.\n", "\n", "# Comparing many search algorithms\n", "\n", "Finally, we compare a host of algorihms (even the slow ones) on some of the easier problems:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "astar_search:\n", " 948 nodes | 109 goal | 4 cost | 112 actions | PourProblem((1, 1, 1), 13)\n", " 1,696 nodes | 190 goal | 10 cost | 204 actions | GreenPourProblem((1, 1, 1), 13)\n", " 3,499 nodes | 389 goal | 9 cost | 397 actions | PourProblem((0, 0, 0), 21)\n", " 4,072 nodes | 454 goal | 21 cost | 463 actions | GreenPourProblem((0, 0, 0), 21)\n", " 124 nodes | 30 goal | 14 cost | 43 actions | PourProblem((0, 0), 8)\n", " 124 nodes | 30 goal | 35 cost | 45 actions | GreenPourProblem((0, 0), 8)\n", " 3,499 nodes | 389 goal | 9 cost | 397 actions | PourProblem((0, 0, 0), 21)\n", " 4,072 nodes | 454 goal | 21 cost | 463 actions | GreenPourProblem((0, 0, 0), 21)\n", " 0 nodes | 1 goal | 0 cost | 0 actions | RouteProblem('A', 'A')\n", " 15 nodes | 6 goal | 418 cost | 9 actions | RouteProblem('A', 'B')\n", " 34 nodes | 15 goal | 910 cost | 23 actions | RouteProblem('N', 'L')\n", " 33 nodes | 14 goal | 805 cost | 21 actions | RouteProblem('E', 'T')\n", " 20 nodes | 9 goal | 445 cost | 13 actions | RouteProblem('O', 'M')\n" ] }, { "ename": "NameError", "evalue": "name 'h2' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_1075091/4164331635.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m report((astar_search, uniform_cost_search, breadth_first_search, breadth_first_bfs, \n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0miterative_deepening_search\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdepth_limited_search\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mgreedy_bfs\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m weighted_astar_search, extra_weighted_astar_search), \n\u001b[1;32m 4\u001b[0m (p1, g1, p2, g2, p3, g3, p4, g4, r0, r1, r2, r3, r4, e1))\n", "\u001b[0;32m/tmp/ipykernel_1075091/1959091182.py\u001b[0m in \u001b[0;36mreport\u001b[0;34m(searchers, problems, verbose)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mp\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mproblems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0mprob\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCountCalls\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0msoln\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msearcher\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprob\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 21\u001b[0m \u001b[0mcounts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mprob\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_counts\u001b[0m\u001b[0;34m;\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0mcounts\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mactions\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msoln\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcost\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msoln\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath_cost\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36mastar_search\u001b[0;34m(problem, h)\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;34m\"\"\"Search nodes with minimum f(n) = g(n) + h(n).\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mh\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 37\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mbest_first_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\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[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36mbest_first_search\u001b[0;34m(problem, f)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"Search nodes with minimum f(node) value first.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mnode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mNode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minitial\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mfrontier\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPriorityQueue\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnode\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mf\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 5\u001b[0m \u001b[0mreached\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minitial\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mnode\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;32mwhile\u001b[0m \u001b[0mfrontier\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/2092060460.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, items, key)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# a heap of (score, item) pairs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mitem\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mitems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\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 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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/tmp/ipykernel_1075091/2092060460.py\u001b[0m in \u001b[0;36madd\u001b[0;34m(self, item)\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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 15\u001b[0m \u001b[0;34m\"\"\"Add item to the queuez.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m \u001b[0mpair\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem\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 17\u001b[0m \u001b[0mheapq\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mheappush\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpair\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/94729273.py\u001b[0m in \u001b[0;36m\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;34m\"\"\"Search nodes with minimum f(n) = g(n) + h(n).\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mh\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 37\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mbest_first_search\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\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[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_1075091/1915594217.py\u001b[0m in \u001b[0;36mh\u001b[0;34m(self, node)\u001b[0m\n\u001b[1;32m 39\u001b[0m for (s, g) in zip(node.state, self.goal) if s != 0)\n\u001b[1;32m 40\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 41\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mh2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnode\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 42\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 43\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mNameError\u001b[0m: name 'h2' is not defined" ] } ], "source": [ "report((astar_search, uniform_cost_search, breadth_first_search, breadth_first_bfs, \n", " iterative_deepening_search, depth_limited_search, greedy_bfs, \n", " weighted_astar_search, extra_weighted_astar_search), \n", " (p1, g1, p2, g2, p3, g3, p4, g4, r0, r1, r2, r3, r4, e1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This confirms some of the things we already knew: A* and uniform-cost search are optimal, but the others are not. A* explores fewer nodes than uniform-cost. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Visualizing Reached States\n", "\n", "I would like to draw a picture of the state space, marking the states that have been reached by the search.\n", "Unfortunately, the *reached* variable is inaccessible inside `best_first_search`, so I will define a new version of `best_first_search` that is identical except that it declares *reached* to be `global`. I can then define `plot_grid_problem` to plot the obstacles of a `GridProblem`, along with the initial and goal states, the solution path, and the states reached during a search." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "def best_first_search(problem, f):\n", " \"Search nodes with minimum f(node) value first.\"\n", " global reached # <<<<<<<<<<< Only change here\n", " node = Node(problem.initial)\n", " frontier = PriorityQueue([node], key=f)\n", " reached = {problem.initial: node}\n", " while frontier:\n", " node = frontier.pop()\n", " if problem.is_goal(node.state):\n", " return node\n", " for child in expand(problem, node):\n", " s = child.state\n", " if s not in reached or child.path_cost < reached[s].path_cost:\n", " reached[s] = child\n", " frontier.add(child)\n", " return failure\n", "\n", "\n", "def plot_grid_problem(grid, solution, reached=(), title='Search', show=True):\n", " \"Use matplotlib to plot the grid, obstacles, solution, and reached.\"\n", " reached = list(reached)\n", " plt.figure(figsize=(16, 10))\n", " plt.axis('off'); plt.axis('equal')\n", " plt.scatter(*transpose(grid.obstacles), marker='s', color='darkgrey')\n", " plt.scatter(*transpose(reached), 1**2, marker='.', c='blue')\n", " plt.scatter(*transpose(path_states(solution)), marker='s', c='blue')\n", " plt.scatter(*transpose([grid.initial]), 9**2, marker='D', c='green')\n", " plt.scatter(*transpose([grid.goal]), 9**2, marker='8', c='red')\n", " if show: plt.show()\n", " print('{} {} search: {:.1f} path cost, {:,d} states reached'\n", " .format(' ' * 10, title, solution.path_cost, len(reached)))\n", " \n", "def plots(grid, weights=(1.4, 2)): \n", " \"\"\"Plot the results of 4 heuristic search algorithms for this grid.\"\"\"\n", " solution = astar_search(grid)\n", " plot_grid_problem(grid, solution, reached, 'A* search')\n", " for weight in weights:\n", " solution = weighted_astar_search(grid, weight=weight)\n", " plot_grid_problem(grid, solution, reached, '(b) Weighted ({}) A* search'.format(weight))\n", " solution = greedy_bfs(grid)\n", " plot_grid_problem(grid, solution, reached, 'Greedy best-first search')\n", " \n", "def transpose(matrix): return list(zip(*matrix))" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "scrolled": false }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " A* search search: 154.2 path cost, 7,418 states reached\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA4sAAAIuCAYAAAAWtZ2KAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAuVUlEQVR4nO3dv48k6X0f4LdWpDikeSsrsiMCzgxBwpE5DRFy6OggoAcwIVxEQYn0HxjkOVDiTEokEAo2ULAtGAdDcGYLNkRA6R1oK7Uiw3Ak7cD0kQtvOdiZvdl5u6urut56f9XzAAfy3pvpfqvqfav6O2/Vp4dxHAMAAAA89qx0BwAAAKiPYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEAAICIYhEA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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " (b) Weighted (1.4) A* search search: 154.2 path cost, 944 states reached\n" ] }, { "data": { "image/png": "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iXAPoCU1n7tq7juV6Q6HQ+4+AAAAUBgriwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAEQUiwAAAET+P/E+FTCdkjWnAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " (b) Weighted (2) A* search search: 162.8 path cost, 782 states reached\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " Greedy best-first search search: 164.5 path cost, 448 states reached\n" ] } ], "source": [ "plots(d3)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "scrolled": false }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA4sAAAIuCAYAAAAWtZ2KAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAA3RElEQVR4nO3dwY4kyXkf8KgRl1jK4FA++a6bYdBD+mxBfgFbIATUHARpT7J50iOISz2CTrIJH1YCD1OAQch+AQr2XbOWfPUjmOI0RC200JQP3b3bU1FVHVmZGfFF5O8HEJSCVZWRkZFZ/U1k/mt3PB4TAAAAPPWidQcAAACIR7EIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABARrEIAABA5hutOwAA9OVwOLxLKX37zP90t9/vX9buDwDrsLIIAEx1rlC81g5AhxSLAAAAZBSLAAAAZBSL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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " A* search search: 133.0 path cost, 2,196 states reached\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " (b) Weighted (1.4) A* search search: 133.0 path cost, 440 states reached\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " (b) Weighted (2) A* search search: 134.2 path cost, 418 states reached\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " Greedy best-first search search: 153.0 path cost, 502 states reached\n" ] } ], "source": [ "plots(d4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# The cost of weighted A* search\n", "\n", "Now I want to try a much simpler grid problem, `d6`, with only a few obstacles. We see that A* finds the optimal path, skirting below the obstacles. Weighterd A* with a weight of 1.4 finds the same optimal path while exploring only 1/3 the number of states. But weighted A* with weight 2 takes the slightly longer path above the obstacles, because that path allowed it to stay closer to the goal in straight-line distance, which it over-weights. And greedy best-first search has a bad showing, not deviating from its path towards the goal until it is almost inside the cup made by the obstacles." ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "scrolled": false }, "outputs": [ { "data": { "image/png": "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KYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAADYcZriAAABrElEQVQAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKYIqAAAAKf8PLmrpHsltQLwAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " A* search search: 124.1 path cost, 3,305 states reached\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA6oAAAJCCAYAAADJHDpFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAAGO9JREFUeJzt3T+PXNd9x+HfHSuCo0BrqTKQKnGTwhEoNq4cyG8gMAIDq0KQXTnRq7Cod6E4SOFChQkEAeI+kGBXaSIlDuAudZpIJiHFUGDeFLtkqOXu8s7u3HO/58zzNIKPaJ3D+UPNR3Pvb6d5ngsAAABS7LY+AAAAADxNqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABBFqAIAABDlha0PAACwlvv37z+oqpe3PkdnHp6enp5sfQjguPlGFQAYmUjdn8cM2JxQBQCGMk01TVO9Pk01bX0WAG5GqAIAo7lTVf9w/lcAOiRUAYDRfFJVPzj/KwAdEqoAwFDmueZ5ro/nueatzwLAzQhVAGBkD7c+AAD78+NpAIAunA9HulNVnzz+tvT5a2c/ZuVm/99t19be5+c/v//oNs8HwJp8owoA9OKyIUkjr7XcByDKNM9u3wAA8iV92zn6N6qnp6d+tA+wKaEKAHCE7t+/f+WHQKEKbM2lvwAAAEQRqgDApqappmmq188vS7XW+LEBSCRUAYCtJQ0wSlpruQ9AFPeoAgCbShpglLS29j6G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AEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAEQRqgAAAET5Pzxfqg2F7ogAAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " (b) Weighted (1.4) A* search search: 124.1 path cost, 975 states reached\n" ] }, { "data": { "image/png": "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hCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABRhCoAAABR/g/qIHhYi9KlRgAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " (b) Weighted (2) A* search search: 128.6 path cost, 879 states reached\n" ] }, { "data": { "image/png": "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FKEKADQhaejImBLAsIQqANCKpKEjY0oAAxKqAEArkoaOjCkBDEioAgBNSBo6MqYEMCyhCgAAQBShCgA0IWnoyJgSwLCEKgDQiqShI2NKAAMSqgBAK5KGjowpAQxIqAIATUgaOjKmBDAsoQoAAEAUoQoANCFp6MiYEsCwhCoA0IqkoSNjSgADEqoAQCuSho6MKQEMqOt776W/zmKx2HiT5vO5l84AwBtYLBYnVfXOoa+D1/n+Btox1VbxjCoAcCgiFYC1hCoAAABRhCoAAABRhCoAAABRhCoAAABRhOp2Tnc8DgBcz/+PZvJ5gbZMslX8eBoAAACieEYVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKEIVAACAKH8DxgVAk+apKx8AAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " Greedy best-first search search: 133.9 path cost, 758 states reached\n" ] } ], "source": [ "plots(d6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the next problem, `d7`, we see a similar story. the optimal path found by A*, and we see that again weighted A* with weight 1.4 does great and with weight 2 ends up erroneously going below the first two barriers, and then makes another mistake by reversing direction back towards the goal and passing above the third barrier. Again, greedy best-first makes bad decisions all around." ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "scrolled": false }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA6oAAAJCCAYAAADJHDpFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAAIABJREFUeJzt3cGqJOmVH/AT16Jpy6gkrwxemdkacbs3XnnQvIARs8m7EJrd2L3yI6irX2FW8hgvxqBFFYgBe28k7L1pewzeyI9gSV2oDRJT4UWliuqsvFkRNzMi/t8Xvx8cGk7fqjhxMjKrzr0Rp4ZxHAsAAABS3G1dAAAAALzLoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyoAAABRDKoAAABEMagCAAAQxaAKAABAFIMqAAAAUQyqAAAARDGoAgAAEMWgCgAAQBSDKgAAAFEMqgAAAEQxqAIAABDFoAoAAEAUgyrQtWGoYRjqk2GoYakcAAC3ZVAFendfVT8//nepHAAANzSM47h1DQCLOf7k876qvhzHGpfIAQBwWwZVAAAAorj1FwAAgCgGVaBJayxJmrNMKame3vsAAPTPoAq0ao0lSXOWKSXV03sfAIDOeUYVaNIaS5LmLFNKqqf3PgAA/TOoAgAAEMWtvwAAAEQxqAJRkpYDpS0RSs+l1ZOUW/M4ANADgyqQJmk5UNoSofRcWj1JuTWPAwDN84wqEGWNZTy3zqXVow95uTWPAwA9MKgCAAAQxa2/AAAARDGoAqtIWmzT6qKc9FxaPUm5tHqScnO/FoB9MKgCa0labNPqopz0XFo9Sbm0epJyc78WgD0Yx1EIIRaPqnGoGj+pGofecmn16ENeLq2epNzcrxVCCLGPsEwJAACAKG79BQAAIIpBFQAAgCgGVeAqSdtDW9ha2nMurZ6kXFo9Sbm0epY4PwCeYOuHZIUQbcdx2cmvqsZP9ppLq0cf8nJp9STl0upZ4vyEEELMj80LEEK0HRW0PXSrXFo9+pCXS6snKZdWzxLnJ4QQYn7Y+gsAAEAUz6gCAAAQxaAKvGePC08sg9EHvdGbtNxSvydAE7a+91gIkRe1w4Un1+TS6tGHvFxaPUm5tHqSckv9nkII0UJsXoAQIi9qhwtPrsml1aMPebm0epJyafUk5Zb6PYUQooWwTAkAAIAonlEFAAAgikEVdiRtqUcvubR69CEvl1ZPUi6tnqRcWj3XngvALFvfeyyEWC8qbKlHL7m0evQhL5dWT1IurZ6kXFo9156LEELMic0LEEKsFxW21KOXXFo9+pCXS6snKZdWT1IurZ5rz0UIIeaEZUoAAABE8YwqAAAAUQyq0AFLPbbNpdWjD3m5tHqScmn1JOXS6mmhD0BHtr73WAhxfZSlHpvm0urRh7xcWj1JubR6knJp9bTQByFEP7F5AUKI66Ms9dg0l1aPPuTl0upJyqXVk5RLq6eFPggh+gnLlAAAAIjiGVUAAACiGFQhWKvLLPaWS6tHH/JyafUk5dLqScql1bPHPgAb2vreYyHE41GNLrPYWy6tHn3Iy6XVk5RLqycpl1bPHvsghNguNi9ACPF4VKPLLPaWS6tHH/JyafUk5dLqScql1bPHPgghtgvLlACAbg1DfVVV39m6jsa8Gsd6tnURwL4ZVAGAbg1D+YvOE4yj5zSBbVmmBBtIWlLRwjKL9FxaPfqQl0urJym35nGYbo/XiGsJwmx977EQe4wKWlIxNZdWT1IurR59yMul1ZOUW/o4VeMonhS7uUaeUo8QYvnYvAAh9hgVtKRiai6tnqRcWj36kJdLqycpt/RxqsatB75WYzfXyFPqEUIsH55RBQC6MFictCQLloBVGVQBgC4MXS1OGqvCHoscLVgCVvStrQuAnhyXLdxX1Zfj+OYvTL3k0upJyqXVow95ubR6knK3/D3rghcvXl763xw9PBwe/X89XCNL1gjclq2/cFv3VfXz4397y6XVk5RLq0cf8nJp9STllvo9ub2erhHXHIRz6y/cUNJ3d/f4HW290YfUXFo9Sblb/p5V9boe4Seq01z6iWq9+QFH09eIn6hCOwyqAEBzhpmLkwyq03xgUD1lwRKwGLf+AgAtmjykfvzxH5asoysze2XDMrCcrf99HCFaiKR/v82/Y5eXS6tHH/JyafUk5Z7666vG8ULEnF/ydfPixYvxsUjqddrrMqduIcTTY/MChGghjn/4/Kpq/GSvubR6knJp9ehDXi6tnqTcU3991XhpeIo5v+Tr5gODakyv016XOXULIZ4emxcgRAtRQd+h3SqXVk9SLq0efcjLpdWTlHvqr68aLw1PMeeXfN34ierydQshnh7DOI4FAJBq7uKkcaxhwXK68fLly0f/Eng4HN72cBhmbba1YAm4CcuUAIB0c5b2vFqsiv2a01MLloCbMKjCiWGoYRjqk+O/kyanN3qjD3oT0ptH3FXVp1V19+ZOsXqWdH4tXDfnvPt141jPjj+lftvrqb+2pT5s1WvgEVvfeyxEWlTQIoakXFo9Sbm0evQhL5dWT1JuytdWjZeekYw5l9aum6nLlLZ+TdJel2vPRQgxLTYvQIi0qKBFDEm5tHqScmn16ENeLq2epNyUr60aLw1FMefS2nUzdZnS1q9J2uty7bkIIaaFZUoAQIzB4qTVTF2mdM5gwRKwMM+oAgBJLE5qgwVLwKIMquxW7wsbLLPQG33IyaXVk5S7lD+j28VJW14353zo144rLlhaqw9bvs7AGVvfeyzEVlGdL2y4dS6tnqRcWj36kJdLqycpd5qvGi89+xhTdw/XzTXLlNZ87dJelyVeZyHE+7F5AUJsFdX5woZb59LqScql1aMPebm0epJyp/mq8dKwE1N3D9fNNcuU1nzt0l6XJV5nIcT7YZkSALCJweKkTV2zTOmcYd6CpaksYoKd8owqALAVi5P6ssRrZBET7JRBlV2wsOH6XFo9Sbm0evQhL5dWT1Lugl0tTtryujnnKb/fOHPB0hxJr8vG7wvYj63vPRZijagZCw2mfu3ecmn1JOXS6tGHvFxaPSm5qvHSM40RNfZ83dx6mdK53Ade40mR9rqs9doLsffYvAAh1oiysOHqXFo9Sbm0evQhL5dWT0quarw0oETU2PN1c+tlSudyH3iNJ0Xa67LWay/E3sMypQlevnz52LKHV4fDwQP+AHDBMHNpUlXVaHHS4m69TOmcYZkFS4+xeIld6nVW8YzqNI/94eoBfwD4sLl/Xlqc1I81X0t/L2OvupxVDKrsQtriihZzafUk5dLq0Ye8XFo9W/bh1HiyfGfc6eKkLa+bc251jPHMgqXjazwpd6nGJetOzMHeGFTZi/uq+vnxv5dyc752b7m0epJyafXoQ14urZ4t+3BOUo1JuTWPcyqtD1Ml1b1lH6B5nlGdYI1nOFjW8TuS91X15Ti+eV7mXG7O1+4tl1ZPUi6tHn3Iy6XVs3auql7XI8axhoQaE3NLH+fFi5ePvi4PD4e7hD4M859xjah7iRw8ptdZxaA6Qa8vPkBLhics5CGfpUnbaeHvN08YVKewdImutPBefgq3/gLQCkNqfyxN4kOWuEZ8lkADDKp059pFBdf8+p5zafUk5dLq6b0PNO29pUlVWddxUm7N40yxRR+mLmNq4VyWyEHPDKr06NpFBUmLE5JyafUk5dLq6b0PtMv7Z15uzeNM0UIfpkp6nX0ewhmeUZ2g1/u+e3X8TuN9BS6uaDmXVk9SLq2eXvtQFxby0Iz3Ft1UZV3HSbmlj3NpmdK5v98k96Hmfz50sXQJqvqdVQyqE/T64gOkGixO6pLFSVl6+vvNYOkSO9bTe/ldbv0FIJEhtT8WJ7EkS5egMwZVmrbEUoKkJQlJubR6knJp9fTUh3NevHj5XtQHFq1snUurZ6PcM++febk1j/NUKX0Yd7p06VIeWmdQpXVbLmzYWy6tnqRcWj099WGqpD64Rubl0upJyq15nKdqtQ9TJV0Pc3oDzfOM6gS93vfdg+N3D++rkcUVLefS6knKpdXTQx/qwmKU409Qv+Hh4RC9GCWtnqRcWj1JuaWPM3eZ0jmt9aE6W7p0Kc9+9DqrGFQn6PXFB0g1XFiMcm5Q9VkM8+3x7zeXPlvOGS0AowG9vpe/tXUBACxn6Gx77scf/2HrEoC2vaoZn4kTB1vbgWEBBlWAvjU9pL7704xL3zEGmGLqQDnzJ69Nf85CKsuUaMatN+U9tiVvjeO0mEurJymXVs9jNbZo6rkk9brVa0Rv8nJrHueWWu3DNb1p4RqB1hhUacmW2/Pk8upJyqXV81iNLZp6Lkm9bvUa0Zu83JrHuaVW+3BNb1q4RqAplilN0OsDyq05flfwvhrZLNhbLq2epFxaPe/mav6GyzRvN25e2lBq62+7ubR6knJLH+cWW3/Paa0PLW8Hnvu19KnXWcWgOkGvLz7Ql6GzxUlV059R9VkM83lPPW6YuR34ChYxcbVe38tu/QXoR1dDar3ZzgmwhbU+f3r73IabMajSjLSlBHvLpdWTlEus59SLFy/fi3rzZ8CnVXU3jjUcf3r55Ny1v/5M7tnU80vqfwvXSFIurZ6k3JrH2UJaH97NjWM9m/JZtWYflugNJDOo0pK0pQR7y6XVk5RLrGeKVvuwxrm02psWc2n1JOXWPM4W0vqwVQ+3vEYglmdUJ+j1vu/WHL8DeF8hSwn2lkurJymXUk9dWP5x/AnqN9x6AdHS52eZUp+5tHqScksfZ6llSlOl9GGpz90Znvz5de250IdeZxWD6gS9vvhAu4aZi5PODaqtfX75LIbb8p663mDpEgF6fS+79RegTZOH1I8//sOSdQDsmaVLsBCDKs24ZlnAnKUCaxynxVxaPUm5rY99xttFHy9evKy/+Zu/PftFrfZhjXNptTct5tLqScqteZwUrV0jU5cu3WIR01q9gRQGVVpy68UHSywl6DmXVk9Sbutjn7rm61rowxrn0mpvWsyl1ZOUW/M4KfZ4jUy1Vm8ggmdUJ+j1vu/WHL/bd18NL65oOZdWT1Jui2PX5QUebxdzrLmAaOlztkypz1xaPUm5pY+z9TKlc/Z0jdT8RUzvfc4tUSPt6XVWMahO0OuLD7RhmLk46Xh7WVX19fnV07lAAu+pbQ3LLWKyeGlnen0vu/UXIN+cJRprLfYA4DpLfV5bvEQXDKo049bLAh5bILDGcVrMpdWTlFvzOGecLut4NvXX9tSHpOvB+0dvWutNC5Jel1vlpi5iSu0XLM2gSkvWWmiwxnFazKXVk5Rb8zin1vi1PfWh92ukxVxaPUm5NY+TLul12fJ6mCqtHpjNM6oT9Hrfd2uO38W7r4YXV7ScS6snKbf0cWri4qStFxAt3QfLlPrMpdWTlFv6OInLlB6T9Lqsnav5S5eqPvBng6VLfel1VjGoTtDriw/kGa5YnHROT59fPZ0LJPCeasNg6RIf0Ot72a2/AFksTgLgXZYusUsGVSKtsQTgscUAWx07PZdWT1Juqd/zjEmLk6b+fi30YatzabU3LebS6knKrXmcXiS9frfKXVq6dO3iJdcSyQyqpFpjCcBjiwG2OnZ6Lq2epNxSv+eppN9vy2tkjXNptTct5tLqScqteZxeJL1+W14jU7mWiOUZ1Ql6ve872fG7c/fV2eKKlnNp9STlbvl71hWLk7ZeQLR0vy1T6jOXVk9SbunjtLRMaaqk12+La6TmL166+Z8DrK/XWcWgOkGvLz6wreHGi5PO6enzq7Nzeey1f3U4HCw3YRU9vad4Y1hu8dIpi5iC9Ppe/tbWBUALhi+Goap+UFW/HD/33R1uxuKk/XrstbfcBLjGq1rnc8RnFYvzjCqRbv1w/5wlAKf54YthqLF+WmP9lxrrp8ehdbMak3ojd5vePOLJi5OmHiOtD0nnslZvWjyXVq+bFnNrHqdnSa/p0tfIpcVLdcXSpXP2eC2xLoMqqdZYQPDYEoC3+eNQ+tMa735cQw013v246u2wulWNEb2Ru2lvzlmixjWOsVa/lz6XtXrT4rm0et20mFvzOD1Lek3TrpEn+V79un5SX/zw+/U//tNP6osf1jD842t/TzjlGdUJer3vO9nxu3P3teVSgj97/mX92Rc/raofVdU/eqe831XVz+oXn39Wv3i+eo0RvQmoJyn31F9fN16ctPUCoqX73dMypZbPJeX9s4fc0sfpcZnSOUmvaco1UvOXLr31z+vv6r/Vv6zv1m9fva67u7t6/Xqo+vuq+tMax7976u/L0/U6qxhUJ+j1xedxb3+S+vtv/+v66Ov3v+D33676nz+q+s//rsodLyzgKYuTzunp88u5wG25DvdreOLSpT8Oqc/qt9+4LfN1Vb2qZ/Xd+ur7htX19fpedusvnHg7pFb96OyQWlX10ddV3/9Z1b/6N1U2snN7FicBsKTZf858r359dkitejNQfKe+qqr6r24D5lYMqkTaainB28VJr+9+XN+83fd9hlVu56aLk87lzlniGGu8T9c4l7V60+K5tHrdtJhb8zhkvfZLXyNTly69m/u39Vd//t367avHhodj/h9U1T+50GaYzKBKqq2WEvygqv6y7l7/w0lVfvR11af/oeqf/XLSl8Mj1ri21zhuT+eyVm9aPJdWr5sWc2seh6zXPu0auf/b+vO/el13ZgdW4xnVCXq97zvZ8TuA97X2ooI//kR1vPvxpGHVs6rcxmLLcyxTysj1dC5L92brepJySx9nL8uUpkp67VOukXdzP6kvfvi8nv/H4fK/ofqqqv5FjeP/ntN7rtPrrGJQnaDXF5/zvvGM6qXbfw2p3MitFied09Pnl3OB23IdMsubZ0//z+uq7537serrqrqr+k1V/UmN46/XLW7fen0v+/E9nBg/H8eq+qyqfla///b5LzKkcjsWJwGQ783w+aev6tl7/7bNH7f+1pt/osaQyk0YVIm09VKCej7e1y8+/6w++vqv682/m/qu39VHX/91vfqnd1XDpAUEPeTS6knKXfnrb7446bFr+1TKUo/Ec1mrNy2eS6vXTYu5NY/DeUnXQ8T7p8b/9d366vt3Vb8Zq179fd39bqx6dVf1G/80DbdmUCXV9ksJfvH8vv74k9XXd/+vqur4359V1WfH/5+yTKGrhQ0N5tLqeazGU632YY1zWas3LZ5Lq9dNi7k1j8N5SddDxvvnzTD6J8/r+V98Wv/9/z6v539Rb273NaRyU55RnaDX+76THb+Ld18BSwneLliq+suq+vc11Gfj5+O4VY1JvZHL741lShm5ns5lT++frXNLH8cypQ9Luh5aeP+wjV5nFYPqBL2++Ex3XLD0g6r65fEZVmhCT59fzgVuy3UIfej1vfytrQuAFhyH019sXQcAAOyBZ1SJtOpigC2XEjSUS6snKZdWz2M1nmq1D2ucy1q9afFcWr1uWsyteRyANAZVUu1nKUE7ubR6knJp9TxW46lW+7DGuazVmxbPpdXrpsXcmscBiOIZ1Ql6ve872fE7vfe186UESbm0epJyafW8m7NMKSPX07ns6f2zdW7p41imBH3odVYxqE7Q64sP9K+nzy/nArflOoQ+9PpedusvAAAAUQyqNKOnxRUt5tLqScql1fNYjada7cMa57JWb1o8l1avmxZzax4HII1BlZb0tLiixVxaPUm5tHoeq/FUq31Y41zW6k2L59LqddNibs3jAETxjOoEvd733Zrjd3/vq+HFFS3n0upJyqXV827OMqWMXE/nsqf3z9a5pY9jmRL0oddZxaA6Qa8vPtC/nj6/nAvclusQ+tDre9mtvwAAAEQxqNKMnhZXtJhLqycpl1bPYzWearUPa5zLWr1p8VxavW5azK15HIA0BlVa0tPiihZzafUk5dLqeazGU632YY1zWas3LZ5Lq9dNi7k1jwMQxTOqE/R633drjt/9va+GF1e0nEurJymXVs+7OcuUMnI9ncue3j9b55Y+jmVK0IdeZxWD6gS9vvhA/3r6/HIucFuuQ+hDr+9lt/4C9O3VzDwAwOYMqjSjp8UVLebS6knKpdXzbu5wODw7HA7Dw8Ph7uHh8OnDw+HucDgMh8PhWat9OCeh10/pTYvn0up102JuzeMApDGo0pKeFle0mEurJymXVk/vfTgnqQ9zetPiubR63bSYW/M4AFE8ozpBr/d9t+b43d/7anhxRcu5tHqScmn19NqHlhcQ9XQurV03LeeWPo5lStCHXmcVg+oEvb74AC3p6bO4p3OhXa5D6EOv72W3/gIAABDFoEozelpc0WIurZ6kXFo9vffhnKQ+zOlNi+fS6nXTYm7N4wCkMajSkp4WV7SYS6snKZdWT+99OCepD3N60+K5tHrdtJhb8zgAUTyjOkGv93235vjd3/tqeHFFy7m0epJyafX02oeWFxD1dC6tXTct55Y+jmVK0IdeZxWD6gS9vvgALenp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AACAKAZVAAAAohhUAQAAiGJQBQAAIIpBFQAAgCgGVQAAAKIYVAEAAIhiUAUAACCKQRUAAIAoBlUAAACiGFQBAACIYlAFAAAgikEVAACAKAZVAAAAohhUAQAAiGJQBQAAIIpBFQAAgCgGVQAAAKIYVAEAAIhiUAUAACCKQRUAAIAoBlUAAACiGFQBAACIYlAFAAAgikEVAACAKAZVAAAAohhUAQAAiGJQBQAAIIpBFQAAgCgGVQAAAKIYVAEAAIhiUAUAACCKQRUAAIAoBlUAAACiGFQBAACIYlAFAAAgikEVAACAKAZVAAAAohhUAQAAiGJQBQAAIIpBFQAAgCgGVQAAAKIYVAEAAIhiUAUAACCKQRUAAIAoBlUAAACiGFQBAACIYlAFAAAgikEVAACAKAZVAAAAohhUAQAAiGJQBQAAIIpBFQAAgCgGVQAAAKIYVAEAAIhiUAUAACCKQRUAAIAoBlUAAACiGFQBAACIYlAFAAAgikEVAACAKAZVAAAAohhUAQAAiGJQBQAAIIpBFQAAgCgGVQAAAKIYVAEAAIhiUAUAACCKQRUAAIAoBlUAAACiGFQBAACIYlAFAAAgikEVAACAKAZVAAAAohhUAQAAiGJQBQAAIIpBFQAAgCgGVQAAAKIYVAEAAIhiUAUAACDK/wcquXLwuqOEZgAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " A* search search: 127.4 path cost, 4,058 states reached\n" ] }, { "data": { "image/png": "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iCKoAgAAEEVQBQAAIIqgCgAAQBRBFQAAgCiCKgAAAFEEVQAAAKIIqgAAAEQRVAEAAIgiqAIAABBFUAUAACCKoAoAAEAUQRUAAIAogioAAABRBFUAAACiCKoAAABEEVQBAACIIqgCAAAQRVAFAAAgiqAKAABAFEEVAACAKIIqAAAAUQRVAAAAogiqAAAARBFUAQAAiCKoAgAAEEVQBQAAIIqgCgAAQBRBFQAAgCiCKgAAAFEEVQAAAKIIqgAAAEQRVAEAAIgiqAIAABBFUAUAACCKoAoAAEAUQRUAAIAogioAAABRBFUAAACiCKoAAABEEVQBAACIIqgCAAAQRVAFAAAgiqAKAABAFEEVAACAKIIqAAAAUQRVAAAAogiqAAAARBFUAQAAiCKoAgAAEEVQBQAAIIqgCgAAQBRBFQAAgCiCKgAAAFEEVQAAAKIIqgAAAEQRVAEAAIgiqAIAABBFUAUAACCKoAoAAEAUQRUAAIAogioAAABRBFUAAACiCKoAAABEEVQBAACIIqgCAAAQRVAFAAAgiqAKAABAFEEVAACAKIIqAAAAUQRVAAAAogiqAAAARBFUAQAAiCKoAgAAEEVQBQAAIIqgCgAAQBRBFQAAgCiCKgAAAFEEVQAAAKIIqgAAAEQRVAEAAIgiqAIAABBFUAUAACCKoAoAAEAUQRUAAIAogioAAABRBFUAAACiCKoAAABEEVQBAACIIqgCAAAQRVAFAAAgiqAKAABAFEEVAACAKIIqAAAAUQRVAAAAogiqAAAARBFUAQAAiCKoAgAAEEVQBQAAIIqgCgAAQBRBFQAAgCiCKgAAAFEEVQAAAKIIqgAAAEQRVAEAAIgiqAIAABBFUAUAACCKoAoAAEAUQRUAAIAogioAAABRBFUAAACi/H9tufMPU4+G/wAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " (b) Weighted (1.4) A* search search: 127.4 path cost, 1,289 states reached\n" ] }, { "data": { "image/png": "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gioAAABRBFUAAACiCKoAAABEEVQBAACIIqgCAAAQRVAFAAAgiqAKAABAFEEVAACAKIIqAAAAUQRVAAAAogiqAAAARBFUAQAAiCKoAgAAEEVQBQAAIIqgCgAAQBRBFQAAgCiCKgAAAFEEVQAAAKIIqgAAAEQRVAEAAIgiqAIAABBFUAUAACCKoAoAAEAUQRUAAIAogioAAABRBFUAAACiCKoAAABEEVQBAACIIqgCAAAQRVAFAAAgiqAKAABAFEEVAACAKIIqAAAAUQRVAAAAogiqAAAARBFUAQAAiCKoAgAAEEVQBQAAIIqgCgAAQBRBFQAAgCiCKgAAAFEEVQAAAKIIqgAAAEQRVAEAAIgiqAIAABBFUAUAACCKoAoAAEAUQRUAAIAogioAAABRBFUAAACiCKoAAABEEVQBAACIIqgCAAAQRVAFAAAgiqAKAABAFEEVAACAKIIqAAAAUQRVAAAAogiqAAAARBFUAQAAiCKoAgAAEEVQBQAAIIqgCgAAQBRBFQAAgCiCKgAAAFEEVQAAAKIIqgAAAEQRVAEAAIgiqAIAABBFUAUAACCKoAoAAEAUQRUAAIAogioAAABRBFUAAACiCKoAAABEEVQBAACIIqgCAAAQRVAFAAAgiqAKAABAFEEVAACAKIIqAAAAUQRVAAAAogiqAAAARBFUAQAAiCKoAgAAEEVQBQAAIIqgCgAAQBRBFQAAgCiCKgAAAFEEVQAAAKIIqgAAAEQRVAEAAIgiqAIAABBFUAUAACCKoAoAAEAUQRUAAIAogioAAABRBFUAAACiCKoAAABEEVQBAACIIqgCAAAQRVAFAAAgiqAKAABAFEEVAACAKIIqAAAAUQRVAAAAogiqAAAARBFUAQAAiCKoAgAAEEVQBQAAIIqgCgAAQBRBFQAAgCiCKgAAAFEEVQAAAKIIqgAAAEQRVAEAAIgiqAIAABBFUAUAACCKoAoAAEAUQRUAAIAogioAAABRBFUAAACiCKoAAABEEVQBAACIIqgCAAAQRVAFAAAgiqAKAABAlP8DscRvdl+TaAMAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " (b) Weighted (2) A* search search: 140.4 path cost, 982 states reached\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA6oAAAJCCAYAAADJHDpFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAAG55JREFUeJzt3c+OZHd9xuHvaYw1MfIYVpayilhFCpbxnghxASyIpZ6FE7xIIL4HFh4vuAcCYmFFjjSNIha5ARDsPRZEyjJbbwLMyI5lizlZdM2kpqeq+9TU+fP+Tj2PZBmOq/ucru5q+zPV9XbX930BAABAirOlLwAAAAC2CVUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAAACiCFUAYFW6rrquq292XXUtH0u8HoC5CFUAYG1er6p/3/y95WOJ1wMwi67v+6WvAQBgNJtnAV+vqo/6vvpWjyVeD8BchCoAsFpdVw+q6uWlr6MxD/u+bi99EcBpE6oAwGp1nWcDn0ffe20qsCyvUQUAmmUIaBruV2BpQhUAaJkhoGm4X4FF+dFfAKBZNw0BVdWjBS+vZWdlYAlYkFAFAFbBcNKkDCwBsxKqAMAqrGs4qa8KeymogSVgTi8sfQEAAM/ryo/57nXv3sU8F9S4O3fO9/4zv28VmJMxJQCgZQZ+5mNgCZiNUAUAWvZRVb1ZNzyjyih23dfuf2ASfvQXAGjW5sdN71dVdV5BOant+/q6YwBj8IwqALByXjo51K1bX+z9Z11X/ZW/Hsx4acCJsfoLAKzCdau/FmufdXFxsff+Oj8/f3J/uV+BJXhGFQBoVtdV13X1zc367EG3Sz8253mG3F9Dbzf0bQGuI1QB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AgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEEWoAgAAEOX/AIS6zUzgLYR1AAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " Greedy best-first search search: 151.6 path cost, 826 states reached\n" ] } ], "source": [ "plots(d7)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Nondeterministic Actions\n", "\n", "To handle problems with nondeterministic problems, we'll replace the `result` method with `results`, which returns a collection of possible result states. We'll represent the solution to a problem not with a `Node`, but with a plan that consist of two types of component: sequences of actions, like `['forward', 'suck']`, and condition actions, like\n", "`{5: ['forward', 'suck'], 7: []}`, which says that if we end up in state 5, then do `['forward', 'suck']`, but if we end up in state 7, then do the empty sequence of actions." ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [], "source": [ "def and_or_search(problem):\n", " \"Find a plan for a problem that has nondterministic actions.\"\n", " return or_search(problem, problem.initial, [])\n", " \n", "def or_search(problem, state, path):\n", " \"Find a sequence of actions to reach goal from state, without repeating states on path.\"\n", " if problem.is_goal(state): return []\n", " if state in path: return failure # check for loops\n", " for action in problem.actions(state):\n", " plan = and_search(problem, problem.results(state, action), [state] + path)\n", " if plan != failure:\n", " return [action] + plan\n", " return failure\n", "\n", "def and_search(problem, states, path):\n", " \"Plan for each of the possible states we might end up in.\"\n", " if len(states) == 1: \n", " return or_search(problem, next(iter(states)), path)\n", " plan = {}\n", " for s in states:\n", " plan[s] = or_search(problem, s, path)\n", " if plan[s] == failure: return failure\n", " return [plan]" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [], "source": [ "class MultiGoalProblem(Problem):\n", " \"\"\"A version of `Problem` with a colllection of `goals` instead of one `goal`.\"\"\"\n", " \n", " def __init__(self, initial=None, goals=(), **kwds): \n", " self.__dict__.update(initial=initial, goals=goals, **kwds)\n", " \n", " def is_goal(self, state): return state in self.goals\n", " \n", "class ErraticVacuum(MultiGoalProblem):\n", " \"\"\"In this 2-location vacuum problem, the suck action in a dirty square will either clean up that square,\n", " or clean up both squares. A suck action in a clean square will either do nothing, or\n", " will deposit dirt in that square. Forward and backward actions are deterministic.\"\"\"\n", " \n", " def actions(self, state): \n", " return ['suck', 'forward', 'backward']\n", " \n", " def results(self, state, action): return self.table[action][state]\n", " \n", " table = {'suck':{1:{5,7}, 2:{4,8}, 3:{7}, 4:{2,4}, 5:{1,5}, 6:{8}, 7:{3,7}, 8:{6,8}},\n", " 'forward': {1:{2}, 2:{2}, 3:{4}, 4:{4}, 5:{6}, 6:{6}, 7:{8}, 8:{8}},\n", " 'backward': {1:{1}, 2:{1}, 3:{3}, 4:{3}, 5:{5}, 6:{5}, 7:{7}, 8:{7}}}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's find a plan to get from state 1 to the goal of no dirt (states 7 or 8):" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['suck', {5: ['forward', 'suck'], 7: []}]" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "and_or_search(ErraticVacuum(1, {7, 8}))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This plan says \"First suck, and if we end up in state 5, go forward and suck again; if we end up in state 7, do nothing because that is a goal.\"\n", "\n", "Here are the plans to get to a goal state starting from any one of the 8 states:" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{1: ['suck', {5: ['forward', 'suck'], 7: []}],\n", " 2: ['suck', {8: [], 4: ['backward', 'suck']}],\n", " 3: ['suck'],\n", " 4: ['backward', 'suck'],\n", " 5: ['forward', 'suck'],\n", " 6: ['suck'],\n", " 7: [],\n", " 8: []}" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{s: and_or_search(ErraticVacuum(s, {7,8})) \n", " for s in range(1, 9)}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Comparing Algorithms on EightPuzzle Problems of Different Lengths" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [], "source": [ "from functools import lru_cache\n", "\n", "def build_table(table, depth, state, problem):\n", " if depth > 0 and state not in table:\n", " problem.initial = state\n", " table[state] = len(astar_search(problem))\n", " for a in problem.actions(state):\n", " build_table(table, depth - 1, problem.result(state, a), problem)\n", " return table\n", "\n", "def invert_table(table):\n", " result = defaultdict(list)\n", " for key, val in table.items():\n", " result[val].append(key)\n", " return result\n", "\n", "goal = (0, 1, 2, 3, 4, 5, 6, 7, 8)\n", "table8 = invert_table(build_table({}, 25, goal, EightPuzzle(goal)))" ] }, { "cell_type": "code", "execution_count": 78, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/plain": [ "2.6724" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def report8(table8, M, Ds=range(2, 25, 2), searchers=(breadth_first_search, astar_misplaced_tiles, astar_search)):\n", " \"Make a table of average nodes generated and effective branching factor\"\n", " for d in Ds:\n", " line = [d]\n", " N = min(M, len(table8[d]))\n", " states = random.sample(table8[d], N)\n", " for searcher in searchers:\n", " nodes = 0\n", " for s in states:\n", " problem = CountCalls(EightPuzzle(s))\n", " searcher(problem)\n", " nodes += problem._counts['result']\n", " nodes = int(round(nodes/N))\n", " line.append(nodes)\n", " line.extend([ebf(d, n) for n in line[1:]])\n", " print('{:2} & {:6} & {:5} & {:5} && {:.2f} & {:.2f} & {:.2f}'\n", " .format(*line))\n", "\n", " \n", "def ebf(d, N, possible_bs=[b/100 for b in range(100, 300)]):\n", " \"Effective Branching Factor\"\n", " return min(possible_bs, key=lambda b: abs(N - sum(b**i for i in range(1, d+1))))\n", "\n", "def edepth_reduction(d, N, b=2.67):\n", " \n", " \n", "\n", "from statistics import mean \n", "\n", "def random_state():\n", " x = list(range(9))\n", " random.shuffle(x)\n", " return tuple(x)\n", "\n", "meanbf = mean(len(e3.actions(random_state())) for _ in range(10000))\n", "meanbf" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{0: 1,\n", " 1: 2,\n", " 2: 4,\n", " 3: 8,\n", " 4: 16,\n", " 5: 20,\n", " 6: 36,\n", " 7: 60,\n", " 8: 87,\n", " 9: 123,\n", " 10: 175,\n", " 11: 280,\n", " 12: 397,\n", " 13: 656,\n", " 14: 898,\n", " 15: 1452,\n", " 16: 1670,\n", " 17: 2677,\n", " 18: 2699,\n", " 19: 4015,\n", " 20: 3472,\n", " 21: 4672,\n", " 22: 3311,\n", " 23: 3898,\n", " 24: 1945,\n", " 25: 1796,\n", " 26: 621,\n", " 27: 368,\n", " 28: 63,\n", " 29: 19,\n", " 30: 0}" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{n: len(v) for (n, v) in table30.items()}" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 24min 7s, sys: 11.6 s, total: 24min 19s\n", "Wall time: 24min 44s\n" ] } ], "source": [ "%time table30 = invert_table(build_table({}, 30, goal, EightPuzzle(goal)))" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 2 & 5 & 6 & 6 && 1.79 & 2.00 & 2.00\n", " 4 & 33 & 12 & 12 && 2.06 & 1.49 & 1.49\n", " 6 & 128 & 24 & 19 && 2.01 & 1.42 & 1.34\n", " 8 & 368 & 48 & 31 && 1.91 & 1.40 & 1.30\n", "10 & 1033 & 116 & 48 && 1.85 & 1.43 & 1.27\n", "12 & 2672 & 279 & 84 && 1.80 & 1.45 & 1.28\n", "14 & 6783 & 678 & 174 && 1.77 & 1.47 & 1.31\n", "16 & 17270 & 1683 & 364 && 1.74 & 1.48 & 1.32\n", "18 & 41558 & 4102 & 751 && 1.72 & 1.49 & 1.34\n", "20 & 91493 & 9905 & 1318 && 1.69 & 1.50 & 1.34\n", "22 & 175921 & 22955 & 2548 && 1.66 & 1.50 & 1.34\n", "24 & 290082 & 53039 & 5733 && 1.62 & 1.50 & 1.36\n", "CPU times: user 6min, sys: 3.63 s, total: 6min 4s\n", "Wall time: 6min 13s\n" ] } ], "source": [ "%time report8(table30, 20, range(26, 31, 2))" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "26 & 395355 & 110372 & 10080 && 1.58 & 1.50 & 1.35\n", "28 & 463234 & 202565 & 22055 && 1.53 & 1.49 & 1.36\n" ] }, { "ename": "ZeroDivisionError", "evalue": "division by zero", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n", "\u001b[0;32m\u001b[0m in \u001b[0;36mreport8\u001b[0;34m(table8, M, Ds, searchers)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0msearcher\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproblem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0mnodes\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0mproblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_counts\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'result'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0mnodes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mround\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnodes\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0mN\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 14\u001b[0m \u001b[0mline\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnodes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mline\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mextend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mebf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mn\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mline\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\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;31mZeroDivisionError\u001b[0m: division by zero" ] } ], "source": [ "%time report8(table30, 20, range(26, 31, 2))" ] }, { "cell_type": "code", "execution_count": 315, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 116 116 ['A']\n", "140 0 140 ['A', 'S']\n", "0 83 83 ['A']\n", "118 0 118 ['A', 'T']\n", "0 45 45 ['A']\n", "75 0 75 ['A', 'Z']\n", "0 176 176 ['B']\n", "101 92 193 ['B', 'P']\n", "211 0 211 ['B', 'F']\n", "0 77 77 ['B']\n", "90 0 90 ['B', 'G']\n", "0 100 100 ['B']\n", "101 0 101 ['B', 'P']\n", "0 80 80 ['B']\n", "85 0 85 ['B', 'U']\n", "0 87 87 ['C']\n", "120 0 120 ['C', 'D']\n", "0 109 109 ['C']\n", "138 0 138 ['C', 'P']\n", "0 128 128 ['C']\n", "146 0 146 ['C', 'R']\n", "0 47 47 ['D']\n", "75 0 75 ['D', 'M']\n", "0 62 62 ['E']\n", "86 0 86 ['E', 'H']\n", "0 98 98 ['F']\n", "99 0 99 ['F', 'S']\n", "0 77 77 ['H']\n", "98 0 98 ['H', 'U']\n", "0 85 85 ['I']\n", "87 0 87 ['I', 'N']\n", "0 78 78 ['I']\n", "92 0 92 ['I', 'V']\n", "0 36 36 ['L']\n", "70 0 70 ['L', 'M']\n", "0 86 86 ['L']\n", "111 0 111 ['L', 'T']\n", "0 136 136 ['O']\n", "151 0 151 ['O', 'S']\n", "0 48 48 ['O']\n", "71 0 71 ['O', 'Z']\n", "0 93 93 ['P']\n", "97 0 97 ['P', 'R']\n", "0 65 65 ['R']\n", "80 0 80 ['R', 'S']\n", "0 127 127 ['U']\n", "142 0 142 ['U', 'V']\n" ] }, { "data": { "text/plain": [ "(1.2698088530709188, 1.2059558858330393)" ] }, "execution_count": 315, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from itertools import combinations\n", "from statistics import median, mean\n", "\n", "# Detour index for Romania\n", "\n", "L = romania.locations\n", "def ratio(a, b): return astar_search(RouteProblem(a, b, map=romania)).path_cost / sld(L[a], L[b])\n", "nums = [ratio(a, b) for a,b in combinations(L, 2) if b in r1.actions(a)]\n", "mean(nums), median(nums) # 1.7, 1.6 # 1.26, 1.2 for adjacent cities" ] }, { "cell_type": "code", "execution_count": 300, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 300, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sld" ] }, { "cell_type": "code", "execution_count": null, "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.10.12" } }, "nbformat": 4, "nbformat_minor": 2 }