{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Depth-Limited Search" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Depth-first search will not find a goal if it searches down a path\n", "that has infinite length. So, in general, depth-first search is not\n", "guaranteed to find a solution, so it is not complete. \n", "\n", "This problem is eliminated by limiting the depth of the search to some\n", "value $l$. However, this introduces another way of preventing depth-first\n", "search from finding the goal. If the goal is deeper than $l$ it will\n", "not be found.\n", "\n", "How would you make an intelligent guess for $l$ for a given search\n", "problem?\n", "\n", "Its time complexity is $O(b^l)$ and its space complexity is $O(bl)$.\n", "What would the space complexity be of the backtracking version of\n", "this search?\n", "\n", "Regular depth-first search is a special case, for which $l=\\infty$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Iterative-Deepening Search" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If a depth-limited depth-first search limited to depth $l$ does not find the goal,\n", "try it again with limit at $l+1$. Continue this until goal is found.\n", "\n", "Make depth-limited depth-first search complete by repeatedly applying\n", "it with greater values for the depth limit $l$.\n", "\n", "Feels like breadth-first search, in that a level is fully explored\n", "before extending the search to the next level. But, unlike\n", "breadth-first search, after one level is fully explored, all nodes\n", "already expanded are thrown away and the search starts with a clear\n", "memory. \n", "\n", "Seems very wasteful! Is it really? How many nodes are generated\n", "at the final level $d$?\n", "\n", "$$b^d$$\n", "\n", "How many nodes are expanded in\n", "the tree on your way to the final level, down to depth $d-1$? \n", "\n", "$$b + b^2 + \\cdots + b^{d-1} = O(b^{d-1})$$\n", "\n", "How much of a waste is it to throw away those $O(b^{d-1})$ nodes?\n", "Say $b=10$ and $d=5$. We are throwing away on the order of $10^4 =\n", "1,000$ nodes, regenerating them and then generating $b^d = 10^5 =\n", "10,000$ new nodes. Regenerating those 1,000 nodes seems trivial\n", "compared to making the 10,000 new ones.\n", "\n", "Our textbook authors say:\n", "\n", "> \"In general, iterative deepening is the preferred uninformed search method when the search space is large and the depth of the solution is not known.\"\n", "\n", "Watch this [short video by Richard Korf](http://www.youtube.com/watch?v=EnX8cQPiB1M), one of the developers of iterative deepening." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Recursive definition" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's discuss the recursive implementation in Figures 3.17 (with\n", "Figure 3.18). Rather than the explicit storage of expanded nodes in a\n", "python dictionary named expanded, we can rely on the local\n", "variables implicitly stored in the function call\n", "stack. \n", "\n", "First, define the recursive depth-limited search function that\n", "generates the children of a state and calls itself recursively on each\n", "of the child states. Let's define it as a mix of python and English.\n", "Let take_action_f be a function that generates one new state given a\n", "current state and a valid action from that state. Also let\n", "actions_f be a function that returns a list of valid actions from a\n", "given state. We will see examples of these in the next lecture notes." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def depth_limited_search(state, goal_state, actions_f, take_action_f, depth_limit):\n", " \n", " # If we have reached the goal, exit, returning an empty solution path.\n", " If state == goal_state, then\n", " return []\n", " \n", " # If we have reached the depth limit, return the string 'cutoff'.\n", " If depth_limit is 0, then\n", " Return the string 'cutoff' to signal that the depth limit was reached\n", " \n", " cutoff_occurred = False\n", " \n", " # For each possible action from state ...\n", " For each action in actions_f(state):\n", " \n", " # Apply the action to the current state to get a next state, named child_state\n", " child_state = take_action_f(state, action)\n", " \n", " # Recursively call this function to continue the search starting from the child_state.\n", " # Decrease by one the depth_limit for this search.\n", " result = depth_limited_search(child_state, goal_state, actions_f, take_action_f, depth_limit - 1)\n", " \n", " # If result was 'cufoff', just note that this happened.\n", " If result is 'cutoff', then\n", " cutoff_occurred = True\n", " \n", " # If result was not 'failure', search succeeded so add childState to front of solution path and\n", " # return that path.\n", " else if result is not 'failure' then\n", " Add child_state to front of partial solution path, in result, returned by depth_limited_search\n", " return result\n", " \n", " # We reach here only if cutoff or failure occurred. Return whichever occurred.\n", " If cutoff_occurred, then\n", " return 'cutoff'\n", " else\n", " return 'failure'" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def iterative_deepening_search(start_state, goal_state, actions_f, take_action_f, max_depth):\n", " \n", " # Conduct multiple searches, starting with smallest depth, then increasing it by 1 each time.\n", " for depth in range(max_depth):\n", " \n", " # Conduct search from startState\n", " result = depth_limited_search(start_state, goal_state, actions_f, take_action_f, depth)\n", " \n", " # If result was failure, return 'failure'.\n", " if result is 'failure':\n", " return 'failure'\n", " \n", " # Otherwise, if result was not cutoff, it succeeded, so add start_state to solution path and return it.\n", " if result is not 'cutoff', then\n", " Add start_state to front of solution path, in result, returned by depth_limited_search \n", " return result\n", " \n", " # If we reach here, no solution found within the max_depth limit.\n", " return 'cutoff'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Bidirectional Search" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If, and this is a big if, every action in a search problem has a known\n", "inverse action allowing search to go backwards, then an $O(b^d)$\n", "search can be reduced to two $O(b^{d/2})$ searches by iteratively, or\n", "simultaneously in parallel, searching forward from the start state and\n", "searching backwards from the goal state. This also assumes there is\n", "one goal state, or a finite number of goal states." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Uninformed Search Summary" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This table is from page 91 of our texbook. Here $b$ is the branching factor, $d$ is the depth of the shallowest solution, $m$ is the maximum depth of the search tree, and $l$ is the depth limit." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "| Criterion | Breadth-First | Depth-First | Depth-Limited | Iterative-Deepening | Bidirectional \n", "| :-: | :-: | :-: | :-: | :-: | :-:\n", "| Complete? | Yes | No | No | Yes | Yes |\n", "| Optimal? | Yes | No | No | Yes | Yes |\n", "| Time | $O(b^d)$ | $O(b^m)$ | $O(b^l)$ | $O(b^d)$ | $O(b^{d/2})$ |\n", "| Space | $O(b^d)$ | $O(bm)$ | $O(bl)$ | $O(bd)$ | $O(b^{d/2})$ |\n" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "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.8.3" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 1 }