search.ipynb 192 ko
Newer Older
Chipe1's avatar
Chipe1 a validé
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
Chipe1's avatar
Chipe1 a validé
   },
   "source": [
    "# Solving problems by Searching\n",
    "\n",
    "This notebook serves as supporting material for topics covered in **Chapter 3 - Solving Problems by Searching** and **Chapter 4 - Beyond Classical Search** from the book *Artificial Intelligence: A Modern Approach.* This notebook uses implementations from [search.py](https://github.com/aimacode/aima-python/blob/master/search.py) module. Let's start by importing everything from search module."
   "cell_type": "code",
   "execution_count": 1,
    "collapsed": true,
Anthony Marakis's avatar
Anthony Marakis a validé
   "outputs": [],
Chipe1's avatar
Chipe1 a validé
   "source": [
    "from search import *\n",
    "\n",
    "# Needed to hide warnings in the matplotlib sections\n",
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\")"
Chipe1's avatar
Chipe1 a validé
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
Chipe1's avatar
Chipe1 a validé
   "source": [
    "## CONTENTS\n",
    "\n",
    "* Overview\n",
    "* Problem\n",
    "* Node\n",
    "* Search Algorithms Visualization\n",
    "* Breadth-First Tree Search\n",
    "* Breadth-First Search\n",
Vinay Varma's avatar
Vinay Varma a validé
    "* Best First Search\n",
    "* Uniform Cost Search\n",
Vinay Varma's avatar
Vinay Varma a validé
    "* Greedy Best First Search\n",
    "* A\\* Search\n",
    "* Genetic Algorithm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## OVERVIEW\n",
    "Here, we learn about problem solving. Building goal-based agents that can plan ahead to solve problems, in particular, navigation problem/route finding problem. First, we will start the problem solving by precisely defining **problems** and their **solutions**. We will look at several general-purpose search algorithms. Broadly, search algorithms are classified into two types:\n",
    "* **Uninformed search algorithms**: Search algorithms which explore the search space without having any information about the problem other than its definition.\n",
    "* Examples:\n",
    "    1. Breadth First Search\n",
    "    2. Depth First Search\n",
    "    3. Depth Limited Search\n",
    "    4. Iterative Deepening Search\n",
    "\n",
    "\n",
    "* **Informed search algorithms**: These type of algorithms leverage any information (heuristics, path cost) on the problem to search through the search space to find the solution efficiently.\n",
    "* Examples:\n",
    "    1. Best First Search\n",
    "    2. Uniform Cost Search\n",
    "    3. A\\* Search\n",
    "    4. Recursive Best First Search\n",
    "\n",
    "*Don't miss the visualisations of these algorithms solving the route-finding problem defined on Romania map at the end of this notebook.*"
Chipe1's avatar
Chipe1 a validé
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
Chipe1's avatar
Chipe1 a validé
   "source": [
    "## PROBLEM\n",
Chipe1's avatar
Chipe1 a validé
    "\n",
    "Let's see how we define a Problem. Run the next cell to see how abstract class `Problem` is defined in the search module."
jeff3456's avatar
jeff3456 a validé
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n",
       "   \"http://www.w3.org/TR/html4/strict.dtd\">\n",
       "\n",
       "<html>\n",
       "<head>\n",
       "  <title></title>\n",
       "  <meta http-equiv=\"content-type\" content=\"text/html; charset=None\">\n",
       "  <style type=\"text/css\">\n",
       "td.linenos { background-color: #f0f0f0; padding-right: 10px; }\n",
       "span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
       "pre { line-height: 125%; }\n",
       "body .hll { background-color: #ffffcc }\n",
       "body  { background: #f8f8f8; }\n",
       "body .c { color: #408080; font-style: italic } /* Comment */\n",
       "body .err { border: 1px solid #FF0000 } /* Error */\n",
       "body .k { color: #008000; font-weight: bold } /* Keyword */\n",
       "body .o { color: #666666 } /* Operator */\n",
       "body .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       "body .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       "body .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       "body .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       "body .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       "body .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       "body .gd { color: #A00000 } /* Generic.Deleted */\n",
       "body .ge { font-style: italic } /* Generic.Emph */\n",
       "body .gr { color: #FF0000 } /* Generic.Error */\n",
       "body .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       "body .gi { color: #00A000 } /* Generic.Inserted */\n",
       "body .go { color: #888888 } /* Generic.Output */\n",
       "body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       "body .gs { font-weight: bold } /* Generic.Strong */\n",
       "body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       "body .gt { color: #0044DD } /* Generic.Traceback */\n",
       "body .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       "body .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       "body .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       "body .kp { color: #008000 } /* Keyword.Pseudo */\n",
       "body .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       "body .kt { color: #B00040 } /* Keyword.Type */\n",
       "body .m { color: #666666 } /* Literal.Number */\n",
       "body .s { color: #BA2121 } /* Literal.String */\n",
       "body .na { color: #7D9029 } /* Name.Attribute */\n",
       "body .nb { color: #008000 } /* Name.Builtin */\n",
       "body .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       "body .no { color: #880000 } /* Name.Constant */\n",
       "body .nd { color: #AA22FF } /* Name.Decorator */\n",
       "body .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       "body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       "body .nf { color: #0000FF } /* Name.Function */\n",
       "body .nl { color: #A0A000 } /* Name.Label */\n",
       "body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       "body .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       "body .nv { color: #19177C } /* Name.Variable */\n",
       "body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       "body .w { color: #bbbbbb } /* Text.Whitespace */\n",
       "body .mb { color: #666666 } /* Literal.Number.Bin */\n",
       "body .mf { color: #666666 } /* Literal.Number.Float */\n",
       "body .mh { color: #666666 } /* Literal.Number.Hex */\n",
       "body .mi { color: #666666 } /* Literal.Number.Integer */\n",
       "body .mo { color: #666666 } /* Literal.Number.Oct */\n",
       "body .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       "body .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       "body .sc { color: #BA2121 } /* Literal.String.Char */\n",
       "body .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       "body .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       "body .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       "body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       "body .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       "body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       "body .sx { color: #008000 } /* Literal.String.Other */\n",
       "body .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       "body .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       "body .ss { color: #19177C } /* Literal.String.Symbol */\n",
       "body .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       "body .fm { color: #0000FF } /* Name.Function.Magic */\n",
       "body .vc { color: #19177C } /* Name.Variable.Class */\n",
       "body .vg { color: #19177C } /* Name.Variable.Global */\n",
       "body .vi { color: #19177C } /* Name.Variable.Instance */\n",
       "body .vm { color: #19177C } /* Name.Variable.Magic */\n",
       "body .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "\n",
       "  </style>\n",
       "</head>\n",
       "<body>\n",
       "<h2></h2>\n",
       "\n",
       "<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Problem</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n",
       "\n",
       "    <span class=\"sd\">&quot;&quot;&quot;The abstract class for a formal problem. You should subclass</span>\n",
       "<span class=\"sd\">    this and implement the methods actions and result, and possibly</span>\n",
       "<span class=\"sd\">    __init__, goal_test, and path_cost. Then you will create instances</span>\n",
       "<span class=\"sd\">    of your subclass and solve them with the various search functions.&quot;&quot;&quot;</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">initial</span><span class=\"p\">,</span> <span class=\"n\">goal</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;The constructor specifies the initial state, and possibly a goal</span>\n",
       "<span class=\"sd\">        state, if there is a unique goal. Your subclass&#39;s constructor can add</span>\n",
       "<span class=\"sd\">        other arguments.&quot;&quot;&quot;</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">initial</span> <span class=\"o\">=</span> <span class=\"n\">initial</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">goal</span> <span class=\"o\">=</span> <span class=\"n\">goal</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">actions</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Return the actions that can be executed in the given</span>\n",
       "<span class=\"sd\">        state. The result would typically be a list, but if there are</span>\n",
       "<span class=\"sd\">        many actions, consider yielding them one at a time in an</span>\n",
       "<span class=\"sd\">        iterator, rather than building them all at once.&quot;&quot;&quot;</span>\n",
       "        <span class=\"k\">raise</span> <span class=\"ne\">NotImplementedError</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">result</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Return the state that results from executing the given</span>\n",
       "<span class=\"sd\">        action in the given state. The action must be one of</span>\n",
       "<span class=\"sd\">        self.actions(state).&quot;&quot;&quot;</span>\n",
       "        <span class=\"k\">raise</span> <span class=\"ne\">NotImplementedError</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">goal_test</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Return True if the state is a goal. The default method compares the</span>\n",
       "<span class=\"sd\">        state to self.goal or checks for state in self.goal if it is a</span>\n",
       "<span class=\"sd\">        list, as specified in the constructor. Override this method if</span>\n",
       "<span class=\"sd\">        checking against a single self.goal is not enough.&quot;&quot;&quot;</span>\n",
       "        <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">goal</span><span class=\"p\">,</span> <span class=\"nb\">list</span><span class=\"p\">):</span>\n",
       "            <span class=\"k\">return</span> <span class=\"n\">is_in</span><span class=\"p\">(</span><span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">goal</span><span class=\"p\">)</span>\n",
       "        <span class=\"k\">else</span><span class=\"p\">:</span>\n",
       "            <span class=\"k\">return</span> <span class=\"n\">state</span> <span class=\"o\">==</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">goal</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">path_cost</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">c</span><span class=\"p\">,</span> <span class=\"n\">state1</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">state2</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Return the cost of a solution path that arrives at state2 from</span>\n",
       "<span class=\"sd\">        state1 via action, assuming cost c to get up to state1. If the problem</span>\n",
       "<span class=\"sd\">        is such that the path doesn&#39;t matter, this function will only look at</span>\n",
       "<span class=\"sd\">        state2.  If the path does matter, it will consider c and maybe state1</span>\n",
       "<span class=\"sd\">        and action. The default method costs 1 for every step in the path.&quot;&quot;&quot;</span>\n",
       "        <span class=\"k\">return</span> <span class=\"n\">c</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">value</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;For optimization problems, each state has a value.  Hill-climbing</span>\n",
       "<span class=\"sd\">        and related algorithms try to maximize this value.&quot;&quot;&quot;</span>\n",
       "        <span class=\"k\">raise</span> <span class=\"ne\">NotImplementedError</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
jeff3456's avatar
jeff3456 a validé
   "source": [
    "psource(Problem)"
Chipe1's avatar
Chipe1 a validé
   ]
  },
  {
   "cell_type": "markdown",
Chipe1's avatar
Chipe1 a validé
   "source": [
    "The `Problem` class has six methods.\n",
    "* `__init__(self, initial, goal)` : This is what is called a `constructor` and is the first method called when you create an instance of the class. `initial` specifies the initial state of our search problem. It represents the start state from where our agent begins its task of exploration to find the goal state(s) which is given in the `goal` parameter.\n",
    "\n",
    "\n",
    "* `actions(self, state)` : This method returns all the possible actions agent can execute in the given state `state`.\n",
    "\n",
    "\n",
Chipe1's avatar
Chipe1 a validé
    "* `result(self, state, action)` : This returns the resulting state if action `action` is taken in the state `state`. This `Problem` class only deals with deterministic outcomes. So we know for sure what every action in a state would result to.\n",
    "* `goal_test(self, state)` : Given a graph state, it checks if it is a terminal state. If the state is indeed a goal state, value of `True` is returned. Else, of course, `False` is returned.\n",
Chipe1's avatar
Chipe1 a validé
    "* `path_cost(self, c, state1, action, state2)` : Return the cost of the path that arrives at `state2` as a result of taking `action` from `state1`, assuming total cost of `c` to get up to `state1`.\n",
    "* `value(self, state)` : This acts as a bit of extra information in problems where we try to optimise a value when we cannot do a goal test."
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NODE\n",
    "\n",
    "Let's see how we define a Node. Run the next cell to see how abstract class `Node` is defined in the search module."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n",
       "   \"http://www.w3.org/TR/html4/strict.dtd\">\n",
       "\n",
       "<html>\n",
       "<head>\n",
       "  <title></title>\n",
       "  <meta http-equiv=\"content-type\" content=\"text/html; charset=None\">\n",
       "  <style type=\"text/css\">\n",
       "td.linenos { background-color: #f0f0f0; padding-right: 10px; }\n",
       "span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
       "pre { line-height: 125%; }\n",
       "body .hll { background-color: #ffffcc }\n",
       "body  { background: #f8f8f8; }\n",
       "body .c { color: #408080; font-style: italic } /* Comment */\n",
       "body .err { border: 1px solid #FF0000 } /* Error */\n",
       "body .k { color: #008000; font-weight: bold } /* Keyword */\n",
       "body .o { color: #666666 } /* Operator */\n",
       "body .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       "body .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       "body .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       "body .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       "body .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       "body .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       "body .gd { color: #A00000 } /* Generic.Deleted */\n",
       "body .ge { font-style: italic } /* Generic.Emph */\n",
       "body .gr { color: #FF0000 } /* Generic.Error */\n",
       "body .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       "body .gi { color: #00A000 } /* Generic.Inserted */\n",
       "body .go { color: #888888 } /* Generic.Output */\n",
       "body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       "body .gs { font-weight: bold } /* Generic.Strong */\n",
       "body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       "body .gt { color: #0044DD } /* Generic.Traceback */\n",
       "body .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       "body .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       "body .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       "body .kp { color: #008000 } /* Keyword.Pseudo */\n",
       "body .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       "body .kt { color: #B00040 } /* Keyword.Type */\n",
       "body .m { color: #666666 } /* Literal.Number */\n",
       "body .s { color: #BA2121 } /* Literal.String */\n",
       "body .na { color: #7D9029 } /* Name.Attribute */\n",
       "body .nb { color: #008000 } /* Name.Builtin */\n",
       "body .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       "body .no { color: #880000 } /* Name.Constant */\n",
       "body .nd { color: #AA22FF } /* Name.Decorator */\n",
       "body .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       "body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       "body .nf { color: #0000FF } /* Name.Function */\n",
       "body .nl { color: #A0A000 } /* Name.Label */\n",
       "body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       "body .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       "body .nv { color: #19177C } /* Name.Variable */\n",
       "body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       "body .w { color: #bbbbbb } /* Text.Whitespace */\n",
       "body .mb { color: #666666 } /* Literal.Number.Bin */\n",
       "body .mf { color: #666666 } /* Literal.Number.Float */\n",
       "body .mh { color: #666666 } /* Literal.Number.Hex */\n",
       "body .mi { color: #666666 } /* Literal.Number.Integer */\n",
       "body .mo { color: #666666 } /* Literal.Number.Oct */\n",
       "body .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       "body .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       "body .sc { color: #BA2121 } /* Literal.String.Char */\n",
       "body .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       "body .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       "body .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       "body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       "body .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       "body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       "body .sx { color: #008000 } /* Literal.String.Other */\n",
       "body .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       "body .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       "body .ss { color: #19177C } /* Literal.String.Symbol */\n",
       "body .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       "body .fm { color: #0000FF } /* Name.Function.Magic */\n",
       "body .vc { color: #19177C } /* Name.Variable.Class */\n",
       "body .vg { color: #19177C } /* Name.Variable.Global */\n",
       "body .vi { color: #19177C } /* Name.Variable.Instance */\n",
       "body .vm { color: #19177C } /* Name.Variable.Magic */\n",
       "body .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "\n",
       "  </style>\n",
       "</head>\n",
       "<body>\n",
       "<h2></h2>\n",
       "\n",
       "<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Node</span><span class=\"p\">:</span>\n",
       "\n",
       "    <span class=\"sd\">&quot;&quot;&quot;A node in a search tree. Contains a pointer to the parent (the node</span>\n",
       "<span class=\"sd\">    that this is a successor of) and to the actual state for this node. Note</span>\n",
       "<span class=\"sd\">    that if a state is arrived at by two paths, then there are two nodes with</span>\n",
       "<span class=\"sd\">    the same state.  Also includes the action that got us to this state, and</span>\n",
       "<span class=\"sd\">    the total path_cost (also known as g) to reach the node.  Other functions</span>\n",
       "<span class=\"sd\">    may add an f and h value; see best_first_graph_search and astar_search for</span>\n",
       "<span class=\"sd\">    an explanation of how the f and h values are handled. You will not need to</span>\n",
       "<span class=\"sd\">    subclass this class.&quot;&quot;&quot;</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">parent</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">path_cost</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Create a search tree Node, derived from a parent by an action.&quot;&quot;&quot;</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span> <span class=\"o\">=</span> <span class=\"n\">state</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">parent</span> <span class=\"o\">=</span> <span class=\"n\">parent</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">action</span> <span class=\"o\">=</span> <span class=\"n\">action</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">path_cost</span> <span class=\"o\">=</span> <span class=\"n\">path_cost</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">depth</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n",
       "        <span class=\"k\">if</span> <span class=\"n\">parent</span><span class=\"p\">:</span>\n",
       "            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">depth</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"o\">.</span><span class=\"n\">depth</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"fm\">__repr__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n",
       "        <span class=\"k\">return</span> <span class=\"s2\">&quot;&lt;Node {}&gt;&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">)</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"fm\">__lt__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">node</span><span class=\"p\">):</span>\n",
       "        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span> <span class=\"o\">&lt;</span> <span class=\"n\">node</span><span class=\"o\">.</span><span class=\"n\">state</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">expand</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">problem</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;List the nodes reachable in one step from this node.&quot;&quot;&quot;</span>\n",
       "        <span class=\"k\">return</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">child_node</span><span class=\"p\">(</span><span class=\"n\">problem</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">)</span>\n",
       "                <span class=\"k\">for</span> <span class=\"n\">action</span> <span class=\"ow\">in</span> <span class=\"n\">problem</span><span class=\"o\">.</span><span class=\"n\">actions</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">)]</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">child_node</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">problem</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;[Figure 3.10]&quot;&quot;&quot;</span>\n",
       "        <span class=\"nb\">next</span> <span class=\"o\">=</span> <span class=\"n\">problem</span><span class=\"o\">.</span><span class=\"n\">result</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">)</span>\n",
       "        <span class=\"k\">return</span> <span class=\"n\">Node</span><span class=\"p\">(</span><span class=\"nb\">next</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span>\n",
       "                    <span class=\"n\">problem</span><span class=\"o\">.</span><span class=\"n\">path_cost</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">path_cost</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">,</span>\n",
       "                                      <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"nb\">next</span><span class=\"p\">))</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">solution</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Return the sequence of actions to go from the root to this node.&quot;&quot;&quot;</span>\n",
       "        <span class=\"k\">return</span> <span class=\"p\">[</span><span class=\"n\">node</span><span class=\"o\">.</span><span class=\"n\">action</span> <span class=\"k\">for</span> <span class=\"n\">node</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"p\">()[</span><span class=\"mi\">1</span><span class=\"p\">:]]</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">path</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Return a list of nodes forming the path from the root to this node.&quot;&quot;&quot;</span>\n",
       "        <span class=\"n\">node</span><span class=\"p\">,</span> <span class=\"n\">path_back</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"p\">[]</span>\n",
       "        <span class=\"k\">while</span> <span class=\"n\">node</span><span class=\"p\">:</span>\n",
       "            <span class=\"n\">path_back</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">node</span><span class=\"p\">)</span>\n",
       "            <span class=\"n\">node</span> <span class=\"o\">=</span> <span class=\"n\">node</span><span class=\"o\">.</span><span class=\"n\">parent</span>\n",
       "        <span class=\"k\">return</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"nb\">reversed</span><span class=\"p\">(</span><span class=\"n\">path_back</span><span class=\"p\">))</span>\n",
       "\n",
       "    <span class=\"c1\"># We want for a queue of nodes in breadth_first_search or</span>\n",
       "    <span class=\"c1\"># astar_search to have no duplicated states, so we treat nodes</span>\n",
       "    <span class=\"c1\"># with the same state as equal. [Problem: this may not be what you</span>\n",
       "    <span class=\"c1\"># want in other contexts.]</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"fm\">__eq__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">other</span><span class=\"p\">):</span>\n",
       "        <span class=\"k\">return</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">other</span><span class=\"p\">,</span> <span class=\"n\">Node</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span> <span class=\"o\">==</span> <span class=\"n\">other</span><span class=\"o\">.</span><span class=\"n\">state</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"fm\">__hash__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n",
       "        <span class=\"k\">return</span> <span class=\"nb\">hash</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">)</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "psource(Node)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `Node` class has nine methods.\n",
    "\n",
Alan Oliveira's avatar
Alan Oliveira a validé
    "* `__init__(self, state, parent, action, path_cost)` : This method creates a node. `parent` represents the node that this is a successor of and `action` is the action required to get from the parent node to this node. `path_cost` is the cost to reach current node from parent node.\n",
    "\n",
    "* `__repr__(self)` : This returns the state of this node.\n",
    "\n",
    "* `__lt__(self, node)` : Given a `node`, this method returns `True` if the state of current node is less than the state of the `node`. Otherwise it returns `False`.\n",
    "\n",
Alan Oliveira's avatar
Alan Oliveira a validé
    "* `expand(self, problem)` : This method lists all the neighbouring(reachable in one step) nodes of current node. \n",
Alan Oliveira's avatar
Alan Oliveira a validé
    "* `child_node(self, problem, action)` : Given an `action`, this method returns the immediate neighbour that can be reached with that `action`.\n",
    "\n",
    "* `solution(self)` : This returns the sequence of actions required to reach this node from the root node. \n",
    "\n",
    "* `path(self)` : This returns a list of all the nodes that lies in the path from the root to this node.\n",
    "\n",
    "* `__eq__(self, other)` : This method returns `True` if the state of current node is equal to the other node. Else it returns `False`.\n",
    "\n",
    "* `__hash__(self)` : This returns the hash of the state of current node."
   ]
  },
Chipe1's avatar
Chipe1 a validé
  {
   "cell_type": "markdown",
Chipe1's avatar
Chipe1 a validé
   "source": [
    "We will use the abstract class `Problem` to define our real **problem** named `GraphProblem`. You can see how we define `GraphProblem` by running the next cell."
jeff3456's avatar
jeff3456 a validé
   ]
  },
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n",
       "   \"http://www.w3.org/TR/html4/strict.dtd\">\n",
       "\n",
       "<html>\n",
       "<head>\n",
       "  <title></title>\n",
       "  <meta http-equiv=\"content-type\" content=\"text/html; charset=None\">\n",
       "  <style type=\"text/css\">\n",
       "td.linenos { background-color: #f0f0f0; padding-right: 10px; }\n",
       "span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
       "pre { line-height: 125%; }\n",
       "body .hll { background-color: #ffffcc }\n",
       "body  { background: #f8f8f8; }\n",
       "body .c { color: #408080; font-style: italic } /* Comment */\n",
       "body .err { border: 1px solid #FF0000 } /* Error */\n",
       "body .k { color: #008000; font-weight: bold } /* Keyword */\n",
       "body .o { color: #666666 } /* Operator */\n",
       "body .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       "body .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       "body .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       "body .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       "body .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       "body .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       "body .gd { color: #A00000 } /* Generic.Deleted */\n",
       "body .ge { font-style: italic } /* Generic.Emph */\n",
       "body .gr { color: #FF0000 } /* Generic.Error */\n",
       "body .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       "body .gi { color: #00A000 } /* Generic.Inserted */\n",
       "body .go { color: #888888 } /* Generic.Output */\n",
       "body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       "body .gs { font-weight: bold } /* Generic.Strong */\n",
       "body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       "body .gt { color: #0044DD } /* Generic.Traceback */\n",
       "body .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       "body .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       "body .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       "body .kp { color: #008000 } /* Keyword.Pseudo */\n",
       "body .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       "body .kt { color: #B00040 } /* Keyword.Type */\n",
       "body .m { color: #666666 } /* Literal.Number */\n",
       "body .s { color: #BA2121 } /* Literal.String */\n",
       "body .na { color: #7D9029 } /* Name.Attribute */\n",
       "body .nb { color: #008000 } /* Name.Builtin */\n",
       "body .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       "body .no { color: #880000 } /* Name.Constant */\n",
       "body .nd { color: #AA22FF } /* Name.Decorator */\n",
       "body .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       "body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       "body .nf { color: #0000FF } /* Name.Function */\n",
       "body .nl { color: #A0A000 } /* Name.Label */\n",
       "body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       "body .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       "body .nv { color: #19177C } /* Name.Variable */\n",
       "body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       "body .w { color: #bbbbbb } /* Text.Whitespace */\n",
       "body .mb { color: #666666 } /* Literal.Number.Bin */\n",
       "body .mf { color: #666666 } /* Literal.Number.Float */\n",
       "body .mh { color: #666666 } /* Literal.Number.Hex */\n",
       "body .mi { color: #666666 } /* Literal.Number.Integer */\n",
       "body .mo { color: #666666 } /* Literal.Number.Oct */\n",
       "body .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       "body .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       "body .sc { color: #BA2121 } /* Literal.String.Char */\n",
       "body .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       "body .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       "body .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       "body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       "body .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       "body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       "body .sx { color: #008000 } /* Literal.String.Other */\n",
       "body .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       "body .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       "body .ss { color: #19177C } /* Literal.String.Symbol */\n",
       "body .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       "body .fm { color: #0000FF } /* Name.Function.Magic */\n",
       "body .vc { color: #19177C } /* Name.Variable.Class */\n",
       "body .vg { color: #19177C } /* Name.Variable.Global */\n",
       "body .vi { color: #19177C } /* Name.Variable.Instance */\n",
       "body .vm { color: #19177C } /* Name.Variable.Magic */\n",
       "body .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "\n",
       "  </style>\n",
       "</head>\n",
       "<body>\n",
       "<h2></h2>\n",
       "\n",
       "<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">GraphProblem</span><span class=\"p\">(</span><span class=\"n\">Problem</span><span class=\"p\">):</span>\n",
       "\n",
       "    <span class=\"sd\">&quot;&quot;&quot;The problem of searching a graph from one node to another.&quot;&quot;&quot;</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">initial</span><span class=\"p\">,</span> <span class=\"n\">goal</span><span class=\"p\">,</span> <span class=\"n\">graph</span><span class=\"p\">):</span>\n",
       "        <span class=\"n\">Problem</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">initial</span><span class=\"p\">,</span> <span class=\"n\">goal</span><span class=\"p\">)</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">graph</span> <span class=\"o\">=</span> <span class=\"n\">graph</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">actions</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">A</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;The actions at a graph node are just its neighbors.&quot;&quot;&quot;</span>\n",
       "        <span class=\"k\">return</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">graph</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">A</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">keys</span><span class=\"p\">())</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">result</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;The result of going to a neighbor is just that neighbor.&quot;&quot;&quot;</span>\n",
       "        <span class=\"k\">return</span> <span class=\"n\">action</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">path_cost</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">cost_so_far</span><span class=\"p\">,</span> <span class=\"n\">A</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">B</span><span class=\"p\">):</span>\n",
       "        <span class=\"k\">return</span> <span class=\"n\">cost_so_far</span> <span class=\"o\">+</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">graph</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">A</span><span class=\"p\">,</span> <span class=\"n\">B</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">infinity</span><span class=\"p\">)</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">find_min_edge</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Find minimum value of edges.&quot;&quot;&quot;</span>\n",
       "        <span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">infinity</span>\n",
       "        <span class=\"k\">for</span> <span class=\"n\">d</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">graph</span><span class=\"o\">.</span><span class=\"n\">dict</span><span class=\"o\">.</span><span class=\"n\">values</span><span class=\"p\">():</span>\n",
       "            <span class=\"n\">local_min</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">d</span><span class=\"o\">.</span><span class=\"n\">values</span><span class=\"p\">())</span>\n",
       "            <span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">,</span> <span class=\"n\">local_min</span><span class=\"p\">)</span>\n",
       "\n",
       "        <span class=\"k\">return</span> <span class=\"n\">m</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">h</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">node</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;h function is straight-line distance from a node&#39;s state to goal.&quot;&quot;&quot;</span>\n",
       "        <span class=\"n\">locs</span> <span class=\"o\">=</span> <span class=\"nb\">getattr</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">graph</span><span class=\"p\">,</span> <span class=\"s1\">&#39;locations&#39;</span><span class=\"p\">,</span> <span class=\"bp\">None</span><span class=\"p\">)</span>\n",
       "        <span class=\"k\">if</span> <span class=\"n\">locs</span><span class=\"p\">:</span>\n",
       "            <span class=\"k\">if</span> <span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"n\">node</span><span class=\"p\">)</span> <span class=\"ow\">is</span> <span class=\"nb\">str</span><span class=\"p\">:</span>\n",
       "                <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">locs</span><span class=\"p\">[</span><span class=\"n\">node</span><span class=\"p\">],</span> <span class=\"n\">locs</span><span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">goal</span><span class=\"p\">]))</span>\n",
       "\n",
       "            <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">locs</span><span class=\"p\">[</span><span class=\"n\">node</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">],</span> <span class=\"n\">locs</span><span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">goal</span><span class=\"p\">]))</span>\n",
       "        <span class=\"k\">else</span><span class=\"p\">:</span>\n",
       "            <span class=\"k\">return</span> <span class=\"n\">infinity</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
Chipe1's avatar
Chipe1 a validé
   "source": [
    "psource(GraphProblem)"
Chipe1's avatar
Chipe1 a validé
   ]
  },
  {
   "cell_type": "markdown",
Chipe1's avatar
Chipe1 a validé
   "source": [
    "Now it's time to define our problem. We will define it by passing `initial`, `goal`, `graph` to `GraphProblem`. So, our problem is to find the goal state starting from the given initial state on the provided graph. Have a look at our romania_map, which is an Undirected Graph containing a dict of nodes as keys and neighbours as values."
Chipe1's avatar
Chipe1 a validé
   ]
  },
  {
   "cell_type": "code",
Anthony Marakis's avatar
Anthony Marakis a validé
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
Chipe1's avatar
Chipe1 a validé
   "outputs": [],
   "source": [
    "romania_map = UndirectedGraph(dict(\n",
    "    Arad=dict(Zerind=75, Sibiu=140, Timisoara=118),\n",
    "    Bucharest=dict(Urziceni=85, Pitesti=101, Giurgiu=90, Fagaras=211),\n",
    "    Craiova=dict(Drobeta=120, Rimnicu=146, Pitesti=138),\n",
    "    Drobeta=dict(Mehadia=75),\n",
    "    Eforie=dict(Hirsova=86),\n",
    "    Fagaras=dict(Sibiu=99),\n",
    "    Hirsova=dict(Urziceni=98),\n",
    "    Iasi=dict(Vaslui=92, Neamt=87),\n",
    "    Lugoj=dict(Timisoara=111, Mehadia=70),\n",
    "    Oradea=dict(Zerind=71, Sibiu=151),\n",
    "    Pitesti=dict(Rimnicu=97),\n",
    "    Rimnicu=dict(Sibiu=80),\n",
    "    Urziceni=dict(Vaslui=142)))\n",
    "\n",
    "romania_map.locations = dict(\n",
    "    Arad=(91, 492), Bucharest=(400, 327), Craiova=(253, 288),\n",
    "    Drobeta=(165, 299), Eforie=(562, 293), Fagaras=(305, 449),\n",
    "    Giurgiu=(375, 270), Hirsova=(534, 350), Iasi=(473, 506),\n",
    "    Lugoj=(165, 379), Mehadia=(168, 339), Neamt=(406, 537),\n",
    "    Oradea=(131, 571), Pitesti=(320, 368), Rimnicu=(233, 410),\n",
    "    Sibiu=(207, 457), Timisoara=(94, 410), Urziceni=(456, 350),\n",
    "    Vaslui=(509, 444), Zerind=(108, 531))"
Chipe1's avatar
Chipe1 a validé
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
Chipe1's avatar
Chipe1 a validé
   },
   "source": [
    "It is pretty straightforward to understand this `romania_map`. The first node **Arad** has three neighbours named **Zerind**, **Sibiu**, **Timisoara**. Each of these nodes are 75, 140, 118 units apart from **Arad** respectively. And the same goes with other nodes.\n",
    "\n",
    "And `romania_map.locations` contains the positions of each of the nodes. We will use the straight line distance (which is different from the one provided in `romania_map`) between two cities in algorithms like A\\*-search and Recursive Best First Search.\n",
    "\n",
    "**Define a problem:**\n",
    "Hmm... say we want to start exploring from **Arad** and try to find **Bucharest** in our romania_map. So, this is how we do it."
Chipe1's avatar
Chipe1 a validé
   ]
  },
  {
   "cell_type": "code",
Anthony Marakis's avatar
Anthony Marakis a validé
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
Chipe1's avatar
Chipe1 a validé
   "source": [
    "romania_problem = GraphProblem('Arad', 'Bucharest', romania_map)"
Chipe1's avatar
Chipe1 a validé
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Romania Map Visualisation\n",
    "Let's have a visualisation of Romania map [Figure 3.2] from the book and see how different searching algorithms perform / how frontier expands in each search algorithm for a simple problem named `romania_problem`."
  {
   "cell_type": "markdown",
   "source": [
    "Have a look at `romania_locations`. It is a dictionary defined in search module. We will use these location values to draw the romania graph using **networkx**."
  {
   "cell_type": "code",
Anthony Marakis's avatar
Anthony Marakis a validé
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'Arad': (91, 492), 'Bucharest': (400, 327), 'Craiova': (253, 288), 'Drobeta': (165, 299), 'Eforie': (562, 293), 'Fagaras': (305, 449), 'Giurgiu': (375, 270), 'Hirsova': (534, 350), 'Iasi': (473, 506), 'Lugoj': (165, 379), 'Mehadia': (168, 339), 'Neamt': (406, 537), 'Oradea': (131, 571), 'Pitesti': (320, 368), 'Rimnicu': (233, 410), 'Sibiu': (207, 457), 'Timisoara': (94, 410), 'Urziceni': (456, 350), 'Vaslui': (509, 444), 'Zerind': (108, 531)}\n"
     ]
    }
   ],
   "source": [
    "romania_locations = romania_map.locations\n",
    "print(romania_locations)"
   ]
  },
  {
   "cell_type": "markdown",
    "Let's start the visualisations by importing necessary modules. We use networkx and matplotlib to show the map in the notebook and we use ipywidgets to interact with the map to see how the searching algorithm works."
  {
   "cell_type": "code",
Anthony Marakis's avatar
Anthony Marakis a validé
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import networkx as nx\n",
    "import matplotlib.pyplot as plt\n",
    "from matplotlib import lines\n",
    "\n",
    "from ipywidgets import interact\n",
    "import ipywidgets as widgets\n",
    "from IPython.display import display\n",
  {
   "cell_type": "markdown",
   "source": [
    "Let's get started by initializing an empty graph. We will add nodes, place the nodes in their location as shown in the book, add edges to the graph."
   ]
  },
  {
   "cell_type": "code",
Anthony Marakis's avatar
Anthony Marakis a validé
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# initialise a graph\n",
    "G = nx.Graph()\n",
    "\n",
    "# use this while labeling nodes in the map\n",
    "node_labels = dict()\n",
    "# use this to modify colors of nodes while exploring the graph.\n",
    "# This is the only dict we send to `show_map(node_colors)` while drawing the map\n",
    "node_colors = dict()\n",
    "\n",
    "for n, p in romania_locations.items():\n",
    "    # add nodes from romania_locations\n",
    "    G.add_node(n)\n",
    "    # add nodes to node_labels\n",
    "    node_labels[n] = n\n",
    "    # node_colors to color nodes while exploring romania map\n",
    "    node_colors[n] = \"white\"\n",
    "\n",
    "# we'll save the initial node colors to a dict to use later\n",
    "initial_node_colors = dict(node_colors)\n",
    "    \n",
    "# positions for node labels\n",
    "node_label_pos = { k:[v[0],v[1]-10]  for k,v in romania_locations.items() }\n",
    "\n",
    "# use this while labeling edges\n",
    "edge_labels = dict()\n",
    "\n",
    "# add edges between cities in romania map - UndirectedGraph defined in search.py\n",
    "for node in romania_map.nodes():\n",
    "    connections = romania_map.get(node)\n",
    "    for connection in connections.keys():\n",
    "        distance = connections[connection]\n",
    "\n",
    "        # add edges to the graph\n",
    "        G.add_edge(node, connection)\n",
    "        # add distances to edge_labels\n",
    "        edge_labels[(node, connection)] = distance"
   ]
  },
  {
   "cell_type": "code",
Anthony Marakis's avatar
Anthony Marakis a validé
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "source": [
    "G = nx.Graph()\n",
    "\n",
    "# use this while labeling nodes in the map\n",
    "node_labels = dict()\n",
    "# use this to modify colors of nodes while exploring the graph.\n",
    "# This is the only dict we send to `show_map(node_colors)` while drawing the map\n",
    "for n, p in romania_locations.items():\n",
    "    # add nodes from romania_locations\n",
    "    G.add_node(n)\n",
    "    # add nodes to node_labels\n",
    "    node_labels[n] = n\n",
    "    # node_colors to color nodes while exploring romania map\n",
    "    node_colors[n] = \"white\"\n",
    "# we'll save the initial node colors to a dict to use later\n",
    "initial_node_colors = dict(node_colors)\n",
    "    \n",
    "# positions for node labels\n",
    "node_label_pos = { k:[v[0],v[1]-10]  for k,v in romania_locations.items() }\n",
    "# use this while labeling edges\n",
    "edge_labels = dict()\n",
    "\n",
    "# add edges between cities in romania map - UndirectedGraph defined in search.py\n",
    "for node in romania_map.nodes():\n",
    "    connections = romania_map.get(node)\n",
    "    for connection in connections.keys():\n",
    "        distance = connections[connection]\n",
    "\n",
    "        # add edges to the graph\n",
    "        G.add_edge(node, connection)\n",
    "        # add distances to edge_labels\n",
    "        edge_labels[(node, connection)] = distance"
   ]
  },
  {
   "cell_type": "markdown",
    "We have completed building our graph based on romania_map and its locations. It's time to display it here in the notebook. This function `show_map(node_colors)` helps us do that. We will be calling this function later on to display the map at each and every interval step while searching, using variety of algorithms from the book."
   "execution_count": null,
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def show_map(node_colors):\n",
    "    # set the size of the plot\n",
    "    plt.figure(figsize=(18,13))\n",
    "    # draw the graph (both nodes and edges) with locations from romania_locations\n",
    "    nx.draw(G, pos = romania_locations, node_color = [node_colors[node] for node in G.nodes()])\n",
    "\n",
    "    # draw labels for nodes\n",
    "    node_label_handles = nx.draw_networkx_labels(G, pos = node_label_pos, labels = node_labels, font_size = 14)\n",
    "    # add a white bounding box behind the node labels\n",
    "    [label.set_bbox(dict(facecolor='white', edgecolor='none')) for label in node_label_handles.values()]\n",
    "\n",
    "    # add edge lables to the graph\n",
    "    nx.draw_networkx_edge_labels(G, pos = romania_locations, edge_labels=edge_labels, font_size = 14)\n",
    "    \n",
    "    # add a legend\n",
    "    white_circle = lines.Line2D([], [], color=\"white\", marker='o', markersize=15, markerfacecolor=\"white\")\n",
    "    orange_circle = lines.Line2D([], [], color=\"orange\", marker='o', markersize=15, markerfacecolor=\"orange\")\n",
    "    red_circle = lines.Line2D([], [], color=\"red\", marker='o', markersize=15, markerfacecolor=\"red\")\n",
    "    gray_circle = lines.Line2D([], [], color=\"gray\", marker='o', markersize=15, markerfacecolor=\"gray\")\n",
    "    green_circle = lines.Line2D([], [], color=\"green\", marker='o', markersize=15, markerfacecolor=\"green\")\n",
    "    plt.legend((white_circle, orange_circle, red_circle, gray_circle, green_circle),\n",
    "               ('Un-explored', 'Frontier', 'Currently Exploring', 'Explored', 'Final Solution'),\n",
    "               numpoints=1,prop={'size':16}, loc=(.8,.75))\n",
    "    \n",
    "    # show the plot. No need to use in notebooks. nx.draw will show the graph itself.\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "We can simply call the function with node_colors dictionary object to display it."
   ]
  },
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
  {
   "cell_type": "markdown",
   "source": [
    "Voila! You see, the romania map as shown in the Figure[3.2] in the book. Now, see how different searching algorithms perform with our problem statements."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## SIMPLE PROBLEM SOLVING AGENT PROGRAM\n",
    "\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "Let us now define a Simple Problem Solving Agent Program. Run the next cell to see how the abstract class `SimpleProblemSolvingAgentProgram` is defined in the search module."
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n",
       "   \"http://www.w3.org/TR/html4/strict.dtd\">\n",
       "\n",
       "<html>\n",
       "<head>\n",
       "  <title></title>\n",
       "  <meta http-equiv=\"content-type\" content=\"text/html; charset=None\">\n",
       "  <style type=\"text/css\">\n",
       "td.linenos { background-color: #f0f0f0; padding-right: 10px; }\n",
       "span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
       "pre { line-height: 125%; }\n",
       "body .hll { background-color: #ffffcc }\n",
       "body  { background: #f8f8f8; }\n",
       "body .c { color: #408080; font-style: italic } /* Comment */\n",
       "body .err { border: 1px solid #FF0000 } /* Error */\n",
       "body .k { color: #008000; font-weight: bold } /* Keyword */\n",
       "body .o { color: #666666 } /* Operator */\n",
       "body .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       "body .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       "body .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       "body .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       "body .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       "body .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       "body .gd { color: #A00000 } /* Generic.Deleted */\n",
       "body .ge { font-style: italic } /* Generic.Emph */\n",
       "body .gr { color: #FF0000 } /* Generic.Error */\n",
       "body .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       "body .gi { color: #00A000 } /* Generic.Inserted */\n",
       "body .go { color: #888888 } /* Generic.Output */\n",
       "body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       "body .gs { font-weight: bold } /* Generic.Strong */\n",
       "body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       "body .gt { color: #0044DD } /* Generic.Traceback */\n",
       "body .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       "body .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       "body .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       "body .kp { color: #008000 } /* Keyword.Pseudo */\n",
       "body .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       "body .kt { color: #B00040 } /* Keyword.Type */\n",
       "body .m { color: #666666 } /* Literal.Number */\n",
       "body .s { color: #BA2121 } /* Literal.String */\n",
       "body .na { color: #7D9029 } /* Name.Attribute */\n",
       "body .nb { color: #008000 } /* Name.Builtin */\n",
       "body .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       "body .no { color: #880000 } /* Name.Constant */\n",
       "body .nd { color: #AA22FF } /* Name.Decorator */\n",
       "body .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       "body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       "body .nf { color: #0000FF } /* Name.Function */\n",
       "body .nl { color: #A0A000 } /* Name.Label */\n",
       "body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       "body .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       "body .nv { color: #19177C } /* Name.Variable */\n",
       "body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       "body .w { color: #bbbbbb } /* Text.Whitespace */\n",
       "body .mb { color: #666666 } /* Literal.Number.Bin */\n",
       "body .mf { color: #666666 } /* Literal.Number.Float */\n",
       "body .mh { color: #666666 } /* Literal.Number.Hex */\n",
       "body .mi { color: #666666 } /* Literal.Number.Integer */\n",
       "body .mo { color: #666666 } /* Literal.Number.Oct */\n",
       "body .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       "body .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       "body .sc { color: #BA2121 } /* Literal.String.Char */\n",
       "body .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       "body .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       "body .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       "body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       "body .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       "body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       "body .sx { color: #008000 } /* Literal.String.Other */\n",
       "body .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       "body .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       "body .ss { color: #19177C } /* Literal.String.Symbol */\n",
       "body .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       "body .fm { color: #0000FF } /* Name.Function.Magic */\n",
       "body .vc { color: #19177C } /* Name.Variable.Class */\n",
       "body .vg { color: #19177C } /* Name.Variable.Global */\n",
       "body .vi { color: #19177C } /* Name.Variable.Instance */\n",
       "body .vm { color: #19177C } /* Name.Variable.Magic */\n",
       "body .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "\n",
       "  </style>\n",
       "</head>\n",
       "<body>\n",
       "<h2></h2>\n",
       "\n",
       "<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">SimpleProblemSolvingAgentProgram</span><span class=\"p\">:</span>\n",
       "\n",
       "    <span class=\"sd\">&quot;&quot;&quot;Abstract framework for a problem-solving agent. [Figure 3.1]&quot;&quot;&quot;</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">initial_state</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;State is an abstract representation of the state</span>\n",
       "<span class=\"sd\">        of the world, and seq is the list of actions required</span>\n",
       "<span class=\"sd\">        to get to a particular state from the initial state(root).&quot;&quot;&quot;</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span> <span class=\"o\">=</span> <span class=\"n\">initial_state</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">seq</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"fm\">__call__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">percept</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;[Figure 3.1] Formulate a goal and problem, then</span>\n",
       "<span class=\"sd\">        search for a sequence of actions to solve it.&quot;&quot;&quot;</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">update_state</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">percept</span><span class=\"p\">)</span>\n",
       "        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">seq</span><span class=\"p\">:</span>\n",
       "            <span class=\"n\">goal</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formulate_goal</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">)</span>\n",
       "            <span class=\"n\">problem</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formulate_problem</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">goal</span><span class=\"p\">)</span>\n",
       "            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">seq</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">search</span><span class=\"p\">(</span><span class=\"n\">problem</span><span class=\"p\">)</span>\n",
       "            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">seq</span><span class=\"p\">:</span>\n",
       "                <span class=\"k\">return</span> <span class=\"bp\">None</span>\n",
       "        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">seq</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">update_state</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">percept</span><span class=\"p\">):</span>\n",
       "        <span class=\"k\">raise</span> <span class=\"ne\">NotImplementedError</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">formulate_goal</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">):</span>\n",
       "        <span class=\"k\">raise</span> <span class=\"ne\">NotImplementedError</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">formulate_problem</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">goal</span><span class=\"p\">):</span>\n",
       "        <span class=\"k\">raise</span> <span class=\"ne\">NotImplementedError</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">search</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">problem</span><span class=\"p\">):</span>\n",
       "        <span class=\"k\">raise</span> <span class=\"ne\">NotImplementedError</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
    "psource(SimpleProblemSolvingAgentProgram)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The SimpleProblemSolvingAgentProgram class has six methods:  \n",
    "\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "* `__init__(self, intial_state=None)`: This is the `contructor` of the class and is the first method to be called when the class is instantiated. It takes in a keyword argument, `initial_state` which is initially `None`. The argument `intial_state` represents the state from which the agent starts.\n",
    "\n",
    "* `__call__(self, percept)`: This method updates the `state` of the agent based on its `percept` using the `update_state` method. It then formulates a `goal` with the help of `formulate_goal` method and a `problem` using the `formulate_problem` method and returns a sequence of actions to solve it (using the `search` method).\n",
    "\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "* `update_state(self, percept)`: This method updates the `state` of the agent based on its `percept`.\n",
    "\n",
    "* `formulate_goal(self, state)`: Given a `state` of the agent, this method formulates the `goal` for it.\n",
    "\n",
    "* `formulate_problem(self, state, goal)`: It is used in problem formulation given a `state` and a `goal` for the `agent`.\n",
    "\n",
    "* `search(self, problem)`: This method is used to search a sequence of `actions` to solve a `problem`."
   ]
  },
  {
   "cell_type": "markdown",
    "## SEARCHING ALGORITHMS VISUALIZATION\n",
    "In this section, we have visualizations of the following searching algorithms:\n",
    "1. Breadth First Tree Search - Implemented\n",
    "2. Depth First Tree Search - Implemented\n",
    "3. Depth First Graph Search - Implemented\n",
    "4. Breadth First Search - Implemented\n",
    "5. Best First Graph Search - Implemented\n",
    "6. Uniform Cost Search - Implemented\n",
    "7. Depth Limited Search\n",
    "8. Iterative Deepening Search\n",
    "9. A\\*-Search - Implemented\n",
    "10. Recursive Best First Search\n",
    "\n",
    "We add the colors to the nodes to have a nice visualisation when displaying. So, these are the different colors we are using in these visuals:\n",
    "* Un-explored nodes - <font color='black'>white</font>\n",
    "* Frontier nodes - <font color='orange'>orange</font>\n",
    "* Currently exploring node - <font color='red'>red</font>\n",
    "* Already explored nodes - <font color='gray'>gray</font>\n",
    "Now, we will define some helper methods to display interactive buttons and sliders when visualising search algorithms."
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def final_path_colors(problem, solution):\n",
    "    \"returns a node_colors dict of the final path provided the problem and solution\"\n",
    "    \n",
    "    # get initial node colors\n",
    "    final_colors = dict(initial_node_colors)\n",
    "    # color all the nodes in solution and starting node to green\n",
    "    final_colors[problem.initial] = \"green\"\n",
    "    for node in solution:\n",
    "        final_colors[node] = \"green\"  \n",
    "    return final_colors\n",
    "\n",
    "\n",
    "def display_visual(user_input, algorithm=None, problem=None):\n",
    "    if user_input == False:\n",
    "        def slider_callback(iteration):\n",
    "            # don't show graph for the first time running the cell calling this function\n",
    "            try:\n",
    "                show_map(all_node_colors[iteration])\n",
    "            except:\n",
    "                pass\n",
    "        def visualize_callback(Visualize):\n",
    "            if Visualize is True:\n",
    "                button.value = False\n",
    "                \n",
    "                global all_node_colors\n",
    "                \n",
    "                iterations, all_node_colors, node = algorithm(problem)\n",
    "                solution = node.solution()\n",
    "                all_node_colors.append(final_path_colors(problem, solution))\n",
    "                \n",
    "                slider.max = len(all_node_colors) - 1\n",
    "                \n",
    "                for i in range(slider.max + 1):\n",
    "                    slider.value = i\n",
    "                     #time.sleep(.5)\n",
    "        \n",
    "        slider = widgets.IntSlider(min=0, max=1, step=1, value=0)\n",
    "        slider_visual = widgets.interactive(slider_callback, iteration = slider)\n",
    "        display(slider_visual)\n",
    "        button = widgets.ToggleButton(value = False)\n",
    "        button_visual = widgets.interactive(visualize_callback, Visualize = button)\n",
    "        display(button_visual)\n",
    "    \n",
    "    if user_input == True:\n",
    "        node_colors = dict(initial_node_colors)\n",
    "        if algorithm == None:\n",
    "            algorithms = {\"Breadth First Tree Search\": breadth_first_tree_search,\n",
    "                          \"Depth First Tree Search\": depth_first_tree_search,\n",
    "                          \"Breadth First Search\": breadth_first_search,\n",
    "                          \"Depth First Graph Search\": depth_first_graph_search,\n",
    "                          \"Uniform Cost Search\": uniform_cost_search,\n",
    "                          \"A-star Search\": astar_search}\n",
    "            algo_dropdown = widgets.Dropdown(description = \"Search algorithm: \",\n",
    "                                             options = sorted(list(algorithms.keys())),\n",
    "                                             value = \"Breadth First Tree Search\")\n",
    "            display(algo_dropdown)\n",
    "        \n",
    "        def slider_callback(iteration):\n",
    "            # don't show graph for the first time running the cell calling this function\n",
    "            try:\n",
    "                show_map(all_node_colors[iteration])\n",
    "            except:\n",
    "                pass\n",
    "        def visualize_callback(Visualize):\n",
    "            if Visualize is True:\n",
    "                button.value = False\n",
    "                \n",
    "                problem = GraphProblem(start_dropdown.value, end_dropdown.value, romania_map)\n",
    "                global all_node_colors\n",
    "                \n",
    "                if algorithm == None:\n",
    "                    user_algorithm = algorithms[algo_dropdown.value]\n",
    "                \n",
    "#                 print(user_algorithm)\n",
    "#                 print(problem)\n",
    "                \n",
    "                iterations, all_node_colors, node = user_algorithm(problem)\n",
    "                solution = node.solution()\n",
    "                all_node_colors.append(final_path_colors(problem, solution))\n",
    "                slider.max = len(all_node_colors) - 1\n",
    "                \n",
    "                for i in range(slider.max + 1):\n",
    "                    slider.value = i\n",
    "#                     time.sleep(.5)\n",
    "        start_dropdown = widgets.Dropdown(description = \"Start city: \",\n",
    "                                          options = sorted(list(node_colors.keys())), value = \"Arad\")\n",
    "        display(start_dropdown)\n",
    "        end_dropdown = widgets.Dropdown(description = \"Goal city: \",\n",
    "                                        options = sorted(list(node_colors.keys())), value = \"Fagaras\")\n",
    "        display(end_dropdown)\n",
    "        \n",
    "        button = widgets.ToggleButton(value = False)\n",
    "        button_visual = widgets.interactive(visualize_callback, Visualize = button)\n",
    "        display(button_visual)\n",
    "        \n",
    "        slider = widgets.IntSlider(min=0, max=1, step=1, value=0)\n",
    "        slider_visual = widgets.interactive(slider_callback, iteration = slider)\n",
    "        display(slider_visual)"
   ]
  },
  {
   "cell_type": "markdown",
    "## BREADTH-FIRST TREE SEARCH\n",
    "We have a working implementation in search module. But as we want to interact with the graph while it is searching, we need to modify the implementation. Here's the modified breadth first tree search."
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def tree_search(problem, frontier):\n",
    "    \"\"\"Search through the successors of a problem to find a goal.\n",
    "    The argument frontier should be an empty queue.\n",
    "    Don't worry about repeated paths to a state. [Figure 3.7]\"\"\"\n",
    "    \n",
    "    # we use these two variables at the time of visualisations\n",
    "    iterations = 0\n",
    "    all_node_colors = []\n",
    "    node_colors = dict(initial_node_colors)\n",
    "    #Adding first node to the queue\n",
    "    frontier.append(Node(problem.initial))\n",
    "    node_colors[Node(problem.initial).state] = \"orange\"\n",
    "    iterations += 1\n",
    "    all_node_colors.append(dict(node_colors))\n",
    "        #Popping first node of queue\n",
    "        # modify the currently searching node to red\n",
    "        node_colors[node.state] = \"red\"\n",
    "        iterations += 1\n",
    "        all_node_colors.append(dict(node_colors))\n",
    "        \n",
    "        if problem.goal_test(node.state):\n",
    "            # modify goal node to green after reaching the goal\n",
    "            node_colors[node.state] = \"green\"\n",
    "            iterations += 1\n",
    "            all_node_colors.append(dict(node_colors))\n",
    "            return(iterations, all_node_colors, node)\n",
    "        frontier.extend(node.expand(problem))\n",
    "           \n",
    "        for n in node.expand(problem):\n",
    "            node_colors[n.state] = \"orange\"\n",
    "            iterations += 1\n",
    "            all_node_colors.append(dict(node_colors))\n",
    "        # modify the color of explored nodes to gray\n",
    "        node_colors[node.state] = \"gray\"\n",
    "        iterations += 1\n",
    "        all_node_colors.append(dict(node_colors))\n",
    "    return None\n",
    "\n",
    "def breadth_first_tree_search(problem):\n",
    "    \"Search the shallowest nodes in the search tree first.\"\n",
    "    iterations, all_node_colors, node = tree_search(problem, FIFOQueue())\n",
    "    return(iterations, all_node_colors, node)"
Anthony Marakis's avatar
Anthony Marakis a validé
    "Now, we use `ipywidgets` to display a slider, a button and our romania map. By sliding the slider we can have a look at all the intermediate steps of a particular search algorithm. By pressing the button **Visualize**, you can see all the steps without interacting with the slider. These two helper functions are the callback functions which are called when we interact with the slider and the button."
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "d55324f7343a4c71a9a2d4da6d037037"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b07a3813dd724c51a9b37f646cf2be25"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "all_node_colors = []\n",
    "romania_problem = GraphProblem('Arad', 'Fagaras', romania_map)\n",
    "display_visual(user_input = False, algorithm = breadth_first_tree_search, problem = romania_problem)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Depth-First Tree Search:\n",
    "Now let's discuss another searching algorithm, Depth-First Tree Search."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "source": [
    "def depth_first_tree_search(problem):\n",
    "    \"Search the deepest nodes in the search tree first.\"\n",
    "    # This algorithm might not work in case of repeated paths\n",
    "    # and may run into an infinite while loop.\n",
    "    iterations, all_node_colors, node = tree_search(problem, Stack())\n",
    "    return(iterations, all_node_colors, node)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "523b10cf84e54798a044ee714b864b52"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "aecea953f6a448c192ac8e173cf46e35"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
    "all_node_colors = []\n",
    "romania_problem = GraphProblem('Arad', 'Oradea', romania_map)\n",
    "display_visual(user_input = False, algorithm = depth_first_tree_search, problem = romania_problem)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
    "## BREADTH-FIRST SEARCH\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "Let's change all the `node_colors` to starting position and define a different problem statement."
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def breadth_first_search(problem):\n",
    "    \"[Figure 3.11]\"\n",
    "    \n",
    "    # we use these two variables at the time of visualisations\n",
    "    iterations = 0\n",
    "    all_node_colors = []\n",
    "    node_colors = dict(initial_node_colors)\n",
    "    \n",
    "    node = Node(problem.initial)\n",
    "    \n",
    "    node_colors[node.state] = \"red\"\n",
    "    iterations += 1\n",
    "    all_node_colors.append(dict(node_colors))\n",
    "      \n",
    "    if problem.goal_test(node.state):\n",
    "        node_colors[node.state] = \"green\"\n",
    "        iterations += 1\n",
    "        all_node_colors.append(dict(node_colors))\n",
    "        return(iterations, all_node_colors, node)\n",
    "    \n",
    "    frontier = FIFOQueue()\n",
    "    frontier.append(node)\n",
    "    \n",
    "    # modify the color of frontier nodes to blue\n",
    "    node_colors[node.state] = \"orange\"\n",
    "    iterations += 1\n",
    "    all_node_colors.append(dict(node_colors))\n",
    "        \n",
    "    explored = set()\n",
    "    while frontier:\n",
    "        node = frontier.pop()\n",
    "        node_colors[node.state] = \"red\"\n",
    "        iterations += 1\n",
    "        all_node_colors.append(dict(node_colors))\n",
    "        \n",
    "        explored.add(node.state)     \n",
    "        \n",
    "        for child in node.expand(problem):\n",
    "            if child.state not in explored and child not in frontier:\n",
    "                if problem.goal_test(child.state):\n",
    "                    node_colors[child.state] = \"green\"\n",
    "                    iterations += 1\n",
    "                    all_node_colors.append(dict(node_colors))\n",
    "                    return(iterations, all_node_colors, child)\n",
    "                frontier.append(child)\n",
    "\n",
    "                node_colors[child.state] = \"orange\"\n",
    "                iterations += 1\n",
    "                all_node_colors.append(dict(node_colors))\n",
    "                    \n",
    "        node_colors[node.state] = \"gray\"\n",
    "        iterations += 1\n",
    "        all_node_colors.append(dict(node_colors))\n",
    "    return None"
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "735a3dea191a42b6bd97fdfd337ea3e7"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "ef445770d70a4b7c9d1544b98a55ca4d"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "all_node_colors = []\n",
    "romania_problem = GraphProblem('Arad', 'Bucharest', romania_map)\n",
    "display_visual(user_input = False, algorithm = breadth_first_search, problem = romania_problem)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Depth-First Graph Search:  \n",
    "Although we have a working implementation in search module, we have to make a few changes in the algorithm to make it suitable for visualization."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": true
   },
   "source": [
    "def graph_search(problem, frontier):\n",
    "    \"\"\"Search through the successors of a problem to find a goal.\n",
    "    The argument frontier should be an empty queue.\n",
    "    If two paths reach a state, only use the first one. [Figure 3.7]\"\"\"\n",
    "    # we use these two variables at the time of visualisations\n",
    "    iterations = 0\n",
    "    all_node_colors = []\n",
    "    node_colors = dict(initial_node_colors)\n",
    "    \n",
    "    frontier.append(Node(problem.initial))\n",
    "    explored = set()\n",
    "    \n",
    "    # modify the color of frontier nodes to orange\n",
    "    node_colors[Node(problem.initial).state] = \"orange\"\n",
    "    iterations += 1\n",
    "    all_node_colors.append(dict(node_colors))\n",
    "      \n",
    "    while frontier:\n",
    "        # Popping first node of queue\n",
    "        node = frontier.pop()\n",
    "        \n",
    "        # modify the currently searching node to red\n",
    "        node_colors[node.state] = \"red\"\n",
    "        iterations += 1\n",
    "        all_node_colors.append(dict(node_colors))\n",
    "        \n",
    "        if problem.goal_test(node.state):\n",
    "            # modify goal node to green after reaching the goal\n",
    "            node_colors[node.state] = \"green\"\n",
    "            iterations += 1\n",
    "            all_node_colors.append(dict(node_colors))\n",
    "            return(iterations, all_node_colors, node)\n",
    "        \n",
    "        explored.add(node.state)\n",
    "        frontier.extend(child for child in node.expand(problem)\n",
    "                        if child.state not in explored and\n",
    "                        child not in frontier)\n",
    "        \n",
    "        for n in frontier:\n",
    "            # modify the color of frontier nodes to orange\n",
    "            node_colors[n.state] = \"orange\"\n",
    "            iterations += 1\n",
    "            all_node_colors.append(dict(node_colors))\n",
    "\n",
    "        # modify the color of explored nodes to gray\n",
    "        node_colors[node.state] = \"gray\"\n",
    "        iterations += 1\n",
    "        all_node_colors.append(dict(node_colors))\n",
    "        \n",
    "    return None\n",
    "\n",
    "\n",
    "def depth_first_graph_search(problem):\n",
    "    \"\"\"Search the deepest nodes in the search tree first.\"\"\"\n",
    "    iterations, all_node_colors, node = graph_search(problem, Stack())\n",
    "    return(iterations, all_node_colors, node)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "61149ffbc02846af97170f8975d4f11d"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "90b1f8f77fdb4207a3570fbe88a0bdf6"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
    "all_node_colors = []\n",
    "romania_problem = GraphProblem('Arad', 'Bucharest', romania_map)\n",
    "display_visual(user_input = False, algorithm = depth_first_graph_search, problem = romania_problem)"
   "cell_type": "markdown",
Vinay Varma's avatar
Vinay Varma a validé
    "## BEST FIRST SEARCH\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "\n",
    "Let's change all the `node_colors` to starting position and define a different problem statement."
Vinay Varma's avatar
Vinay Varma a validé
   "execution_count": 21,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def best_first_graph_search(problem, f):\n",
    "    \"\"\"Search the nodes with the lowest f scores first.\n",
    "    You specify the function f(node) that you want to minimize; for example,\n",
    "    if f is a heuristic estimate to the goal, then we have greedy best\n",
    "    first search; if f is node.depth then we have breadth-first search.\n",
    "    There is a subtlety: the line \"f = memoize(f, 'f')\" means that the f\n",
    "    values will be cached on the nodes as they are computed. So after doing\n",
    "    a best first search you can examine the f values of the path returned.\"\"\"\n",
    "    \n",
    "    # we use these two variables at the time of visualisations\n",
    "    iterations = 0\n",
    "    all_node_colors = []\n",
    "    node_colors = dict(initial_node_colors)\n",
    "    \n",
    "    f = memoize(f, 'f')\n",
    "    node = Node(problem.initial)\n",
    "    \n",
    "    node_colors[node.state] = \"red\"\n",
    "    iterations += 1\n",
    "    all_node_colors.append(dict(node_colors))\n",
    "    \n",
    "    if problem.goal_test(node.state):\n",
    "        node_colors[node.state] = \"green\"\n",
    "        iterations += 1\n",
    "        all_node_colors.append(dict(node_colors))\n",
    "        return(iterations, all_node_colors, node)\n",
    "    \n",
    "    frontier = PriorityQueue(min, f)\n",
    "    frontier.append(node)\n",
    "    \n",
    "    node_colors[node.state] = \"orange\"\n",
    "    iterations += 1\n",
    "    all_node_colors.append(dict(node_colors))\n",
    "    \n",
    "    explored = set()\n",
    "    while frontier:\n",
    "        node = frontier.pop()\n",
    "        \n",
    "        node_colors[node.state] = \"red\"\n",
    "        iterations += 1\n",
    "        all_node_colors.append(dict(node_colors))\n",
    "        \n",
    "        if problem.goal_test(node.state):\n",
    "            node_colors[node.state] = \"green\"\n",
    "            iterations += 1\n",
    "            all_node_colors.append(dict(node_colors))\n",
    "            return(iterations, all_node_colors, node)\n",
    "        \n",
    "        explored.add(node.state)\n",
    "        for child in node.expand(problem):\n",
    "            if child.state not in explored and child not in frontier:\n",
    "                frontier.append(child)\n",
    "                node_colors[child.state] = \"orange\"\n",
    "                iterations += 1\n",
    "                all_node_colors.append(dict(node_colors))\n",
    "            elif child in frontier:\n",
    "                incumbent = frontier[child]\n",
    "                if f(child) < f(incumbent):\n",
    "                    del frontier[incumbent]\n",
    "                    frontier.append(child)\n",
    "                    node_colors[child.state] = \"orange\"\n",
    "                    iterations += 1\n",
    "                    all_node_colors.append(dict(node_colors))\n",
    "\n",
    "        node_colors[node.state] = \"gray\"\n",
    "        iterations += 1\n",
    "        all_node_colors.append(dict(node_colors))\n",
Vinay Varma's avatar
Vinay Varma a validé
    "    return None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## UNIFORM COST SEARCH\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "Let's change all the `node_colors` to starting position and define a different problem statement."
Vinay Varma's avatar
Vinay Varma a validé
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": true
   },
Vinay Varma's avatar
Vinay Varma a validé
   "outputs": [],
   "source": [
    "def uniform_cost_search(problem):\n",
    "    \"[Figure 3.14]\"\n",
Vinay Varma's avatar
Vinay Varma a validé
    "    #Uniform Cost Search uses Best First Search algorithm with f(n) = g(n)\n",
    "    iterations, all_node_colors, node = best_first_graph_search(problem, lambda node: node.path_cost)\n",
    "    return(iterations, all_node_colors, node)"
   "cell_type": "code",
   "execution_count": 23,
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
Vinay Varma's avatar
Vinay Varma a validé
       "model_id": "46b8200b4a8f47e7b18145234a8469da"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
Vinay Varma's avatar
Vinay Varma a validé
       "model_id": "ca9b2d01bbd5458bb037585c719d73fc"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
    "all_node_colors = []\n",
    "romania_problem = GraphProblem('Arad', 'Bucharest', romania_map)\n",
    "display_visual(user_input = False, algorithm = uniform_cost_search, problem = romania_problem)"
   "cell_type": "markdown",
   "metadata": {},
Vinay Varma's avatar
Vinay Varma a validé
    "## GREEDY BEST FIRST SEARCH\n",
    "Let's change all the node_colors to starting position and define a different problem statement."
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
Vinay Varma's avatar
Vinay Varma a validé
    "def greedy_best_first_search(problem, h=None):\n",
    "    \"\"\"Greedy Best-first graph search is an informative searching algorithm with f(n) = h(n).\n",
    "    You need to specify the h function when you call best_first_search, or\n",
    "    else in your Problem subclass.\"\"\"\n",
    "    h = memoize(h or problem.h, 'h')\n",
Vinay Varma's avatar
Vinay Varma a validé
    "    iterations, all_node_colors, node = best_first_graph_search(problem, lambda n: h(n))\n",
    "    return(iterations, all_node_colors, node)"
Vinay Varma's avatar
Vinay Varma a validé
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
Vinay Varma's avatar
Vinay Varma a validé
       "model_id": "e3ddd0260d7d4a8aa62d610976b9568a"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
Vinay Varma's avatar
Vinay Varma a validé
       "model_id": "dae485b1f4224c34a88de42d252da76c"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
    "all_node_colors = []\n",
Vinay Varma's avatar
Vinay Varma a validé
    "romania_problem = GraphProblem('Arad', 'Bucharest', romania_map)\n",
    "display_visual(user_input = False, algorithm = greedy_best_first_search, problem = romania_problem)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A\\* SEARCH\n",
    "\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "Let's change all the `node_colors` to starting position and define a different problem statement."
Vinay Varma's avatar
Vinay Varma a validé
   "execution_count": 25,
   "metadata": {
    "collapsed": true
   },
Vinay Varma's avatar
Vinay Varma a validé
   "outputs": [],
   "source": [
    "def astar_search(problem, h=None):\n",
    "    \"\"\"A* search is best-first graph search with f(n) = g(n)+h(n).\n",
    "    You need to specify the h function when you call astar_search, or\n",
    "    else in your Problem subclass.\"\"\"\n",
    "    h = memoize(h or problem.h, 'h')\n",
    "    iterations, all_node_colors, node = best_first_graph_search(problem, lambda n: n.path_cost + h(n))\n",
    "    return(iterations, all_node_colors, node)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
Vinay Varma's avatar
Vinay Varma a validé
       "model_id": "15a78d815f0c4ea589cdd5ad40bc8794"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
Vinay Varma's avatar
Vinay Varma a validé
       "model_id": "10450687dd574be2a380e9e40403fa83"
      }
     },
     "metadata": {},
     "output_type": "display_data"
Vinay Varma's avatar
Vinay Varma a validé
    }
   ],
   "source": [
    "all_node_colors = []\n",
    "romania_problem = GraphProblem('Arad', 'Bucharest', romania_map)\n",
    "display_visual(user_input = False, algorithm = astar_search, problem = romania_problem)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
Vinay Varma's avatar
Vinay Varma a validé
       "model_id": "9019790cf8324d73966373bb3f5373a8"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
Vinay Varma's avatar
Vinay Varma a validé
       "model_id": "b8a3195598da472d996e4e8b81595cb7"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
Vinay Varma's avatar
Vinay Varma a validé
       "model_id": "aabe167a0d6440f0a020df8a85a9206c"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
Vinay Varma's avatar
Vinay Varma a validé
       "model_id": "25d146d187004f4f9db6a7dccdbc7e93"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
Vinay Varma's avatar
Vinay Varma a validé
       "model_id": "68d532810a9e46309415fd353c474a4d"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "all_node_colors = []\n",
Vinay Varma's avatar
Vinay Varma a validé
    "# display_visual(user_input = True, algorithm = breadth_first_tree_search)\n",
    "display_visual(user_input = True)"
surya saini's avatar
surya saini a validé
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A* Heuristics\n",
surya saini's avatar
surya saini a validé
    "\n",
    "Different heuristics provide different efficiency in solving A* problems which are generally defined by the number of explored nodes as well as the branching factor. With the classic 8 puzzle we can show the efficiency of different heuristics through the number of explored nodes.\n",
surya saini's avatar
surya saini a validé
    "\n",
    "### 8 Puzzle Problem\n",
surya saini's avatar
surya saini a validé
    "\n",
    "The *8 Puzzle Problem* consists of a 3x3 tray in which the goal is to get the initial configuration to the goal state by shifting the numbered tiles into the blank space.\n",
surya saini's avatar
surya saini a validé
    "\n",
    "example:- \n",
surya saini's avatar
surya saini a validé
    "\n",
    "              Initial State                        Goal State\n",
    "              | 7 | 2 | 4 |                       | 0 | 1 | 2 |\n",
    "              | 5 | 0 | 6 |                       | 3 | 4 | 5 |\n",
    "              | 8 | 3 | 1 |                       | 6 | 7 | 8 |\n",
    "              \n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "We have a total of 9 blank tiles giving us a total of 9! initial configuration but not all of these are solvable. The solvability of a configuration can be checked by calculating the Inversion Permutation. If the total Inversion Permutation is even then the initial configuration is solvable else the initial configuration is not solvable which means that only 9!/2 initial states lead to a solution.\n",
surya saini's avatar
surya saini a validé
    "\n",
    "#### Heuristics :-\n",
surya saini's avatar
surya saini a validé
    "\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "1) Manhattan Distance:- For the 8 puzzle problem Manhattan distance is defined as the distance of a tile from its goal state( for the tile numbered '1' in the initial configuration Manhattan distance is 4 \"2 for left and 2 for upward displacement\").\n",
surya saini's avatar
surya saini a validé
    "\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "2) No. of Misplaced Tiles:- The heuristic calculates the number of misplaced tiles between the current state and goal state.\n",
surya saini's avatar
surya saini a validé
    "\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "3) Sqrt of Manhattan Distance:- It calculates the square root of Manhattan distance.\n",
surya saini's avatar
surya saini a validé
    "\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "4) Max Heuristic:- It assign the score as the maximum between \"Manhattan Distance\" and \"No. of Misplaced Tiles\". "
surya saini's avatar
surya saini a validé
   ]
  },
  {
   "cell_type": "code",
Anthony Marakis's avatar
Anthony Marakis a validé
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
surya saini's avatar
surya saini a validé
   "outputs": [],
   "source": [
Anthony Marakis's avatar
Anthony Marakis a validé
    "# Heuristics for 8 Puzzle Problem\n",
surya saini's avatar
surya saini a validé
    "def linear(state,goal):\n",
    "    return sum([1 if state[i] != goal[i] else 0 for i in range(8)])\n",
    "\n",
    "def manhanttan(state,goal):\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "    index_goal = {0:[2,2], 1:[0,0], 2:[0,1], 3:[0,2], 4:[1,0], 5:[1,1], 6:[1,2], 7:[2,0], 8:[2,1]}\n",
    "    index_state = {}\n",
    "    index = [[0,0], [0,1], [0,2], [1,0], [1,1], [1,2], [2,0], [2,1], [2,2]]\n",
    "    x, y = 0, 0\n",
    "    \n",
    "    for i in range(len(state)):\n",
    "        index_state[state[i]] = index[i]\n",
    "    \n",
    "    mhd = 0\n",
    "    \n",
    "    for i in range(8):\n",
    "        for j in range(2):\n",
    "            mhd = abs(index_goal[i][j] - index_state[i][j]) + mhd\n",
    "    \n",
    "    return mhd\n",
surya saini's avatar
surya saini a validé
    "\n",
    "def sqrt_manhanttan(state,goal):\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "    index_goal = {0:[2,2], 1:[0,0], 2:[0,1], 3:[0,2], 4:[1,0], 5:[1,1], 6:[1,2], 7:[2,0], 8:[2,1]}\n",
    "    index_state = {}\n",
    "    index = [[0,0], [0,1], [0,2], [1,0], [1,1], [1,2], [2,0], [2,1], [2,2]]\n",
    "    x, y = 0, 0\n",
    "    \n",
    "    for i in range(len(state)):\n",
    "        index_state[state[i]] = index[i]\n",
    "    \n",
    "    mhd = 0\n",
    "    \n",
    "    for i in range(8):\n",
    "        for j in range(2):\n",
    "            mhd = (index_goal[i][j] - index_state[i][j])**2 + mhd\n",
    "    \n",
    "    return math.sqrt(mhd)\n",
surya saini's avatar
surya saini a validé
    "\n",
    "def max_heuristic(state,goal):\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "    score1 = manhanttan(state, goal)\n",
    "    score2 = linear(state, goal)\n",
    "    return max(score1, score2)"
surya saini's avatar
surya saini a validé
   ]
  },
  {
   "cell_type": "code",
Anthony Marakis's avatar
Anthony Marakis a validé
   "execution_count": 12,
surya saini's avatar
surya saini a validé
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
Anthony Marakis's avatar
Anthony Marakis a validé
      "Number of explored nodes by the following heuristic are:  145\n",
surya saini's avatar
surya saini a validé
      "[2, 4, 3, 1, 5, 6, 7, 8, 0]\n",
Anthony Marakis's avatar
Anthony Marakis a validé
      "[2, 4, 3, 1, 5, 6, 7, 0, 8]\n",
      "[2, 4, 3, 1, 0, 6, 7, 5, 8]\n",
      "[2, 0, 3, 1, 4, 6, 7, 5, 8]\n",
      "[0, 2, 3, 1, 4, 6, 7, 5, 8]\n",
      "[1, 2, 3, 0, 4, 6, 7, 5, 8]\n",
      "[1, 2, 3, 4, 0, 6, 7, 5, 8]\n",
      "[1, 2, 3, 4, 5, 6, 7, 0, 8]\n",
      "[1, 2, 3, 4, 5, 6, 7, 8, 0]\n",
Anthony Marakis's avatar
Anthony Marakis a validé
      "Number of explored nodes by the following heuristic are:  153\n",
      "[2, 4, 3, 1, 5, 6, 7, 8, 0]\n",
Anthony Marakis's avatar
Anthony Marakis a validé
      "[2, 4, 3, 1, 5, 6, 7, 0, 8]\n",
      "[2, 4, 3, 1, 0, 6, 7, 5, 8]\n",
      "[2, 0, 3, 1, 4, 6, 7, 5, 8]\n",
      "[0, 2, 3, 1, 4, 6, 7, 5, 8]\n",
      "[1, 2, 3, 0, 4, 6, 7, 5, 8]\n",
      "[1, 2, 3, 4, 0, 6, 7, 5, 8]\n",
      "[1, 2, 3, 4, 5, 6, 7, 0, 8]\n",
      "[1, 2, 3, 4, 5, 6, 7, 8, 0]\n",
Anthony Marakis's avatar
Anthony Marakis a validé
      "Number of explored nodes by the following heuristic are:  145\n",
      "[2, 4, 3, 1, 5, 6, 7, 8, 0]\n",
Anthony Marakis's avatar
Anthony Marakis a validé
      "[2, 4, 3, 1, 5, 6, 7, 0, 8]\n",
      "[2, 4, 3, 1, 0, 6, 7, 5, 8]\n",
      "[2, 0, 3, 1, 4, 6, 7, 5, 8]\n",
      "[0, 2, 3, 1, 4, 6, 7, 5, 8]\n",
      "[1, 2, 3, 0, 4, 6, 7, 5, 8]\n",
      "[1, 2, 3, 4, 0, 6, 7, 5, 8]\n",
      "[1, 2, 3, 4, 5, 6, 7, 0, 8]\n",
      "[1, 2, 3, 4, 5, 6, 7, 8, 0]\n",
Anthony Marakis's avatar
Anthony Marakis a validé
      "Number of explored nodes by the following heuristic are:  169\n",
      "[2, 4, 3, 1, 5, 6, 7, 8, 0]\n",
Anthony Marakis's avatar
Anthony Marakis a validé
      "[2, 4, 3, 1, 5, 6, 7, 0, 8]\n",
      "[2, 4, 3, 1, 0, 6, 7, 5, 8]\n",
      "[2, 0, 3, 1, 4, 6, 7, 5, 8]\n",
      "[0, 2, 3, 1, 4, 6, 7, 5, 8]\n",
      "[1, 2, 3, 0, 4, 6, 7, 5, 8]\n",
      "[1, 2, 3, 4, 0, 6, 7, 5, 8]\n",
      "[1, 2, 3, 4, 5, 6, 7, 0, 8]\n",
surya saini's avatar
surya saini a validé
      "[1, 2, 3, 4, 5, 6, 7, 8, 0]\n"
     ]
    }
   ],
   "source": [
    "# Solving the puzzle \n",
    "puzzle = EightPuzzle()\n",
    "puzzle.checkSolvability([2,4,3,1,5,6,7,8,0]) # checks whether the initialized configuration is solvable or not\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "puzzle.solve([2,4,3,1,5,6,7,8,0], [1,2,3,4,5,6,7,8,0],max_heuristic) # Max_heuristic\n",
    "puzzle.solve([2,4,3,1,5,6,7,8,0], [1,2,3,4,5,6,7,8,0],linear) # Linear\n",
    "puzzle.solve([2,4,3,1,5,6,7,8,0], [1,2,3,4,5,6,7,8,0],manhanttan) # Manhattan\n",
    "puzzle.solve([2,4,3,1,5,6,7,8,0], [1,2,3,4,5,6,7,8,0],sqrt_manhanttan) # Sqrt_manhattan"
2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## HILL CLIMBING\n",
    "\n",
    "Hill Climbing is a heuristic search used for optimization problems.\n",
    "Given a large set of inputs and a good heuristic function, it tries to find a sufficiently good solution to the problem. \n",
    "This solution may or may not be the global optimum.\n",
    "The algorithm is a variant of generate and test algorithm. \n",
    "<br>\n",
    "As a whole, the algorithm works as follows:\n",
    "- Evaluate the initial state.\n",
    "- If it is equal to the goal state, return.\n",
    "- Find a neighboring state (one which is heuristically similar to the current state)\n",
    "- Evaluate this state. If it is closer to the goal state than before, replace the initial state with this state and repeat these steps.\n",
    "<br>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n",
       "   \"http://www.w3.org/TR/html4/strict.dtd\">\n",
       "\n",
       "<html>\n",
       "<head>\n",
       "  <title></title>\n",
       "  <meta http-equiv=\"content-type\" content=\"text/html; charset=None\">\n",
       "  <style type=\"text/css\">\n",
       "td.linenos { background-color: #f0f0f0; padding-right: 10px; }\n",
       "span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
       "pre { line-height: 125%; }\n",
       "body .hll { background-color: #ffffcc }\n",
       "body  { background: #f8f8f8; }\n",
       "body .c { color: #408080; font-style: italic } /* Comment */\n",
       "body .err { border: 1px solid #FF0000 } /* Error */\n",
       "body .k { color: #008000; font-weight: bold } /* Keyword */\n",
       "body .o { color: #666666 } /* Operator */\n",
       "body .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       "body .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       "body .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       "body .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       "body .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       "body .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       "body .gd { color: #A00000 } /* Generic.Deleted */\n",
       "body .ge { font-style: italic } /* Generic.Emph */\n",
       "body .gr { color: #FF0000 } /* Generic.Error */\n",
       "body .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       "body .gi { color: #00A000 } /* Generic.Inserted */\n",
       "body .go { color: #888888 } /* Generic.Output */\n",
       "body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       "body .gs { font-weight: bold } /* Generic.Strong */\n",
       "body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       "body .gt { color: #0044DD } /* Generic.Traceback */\n",
       "body .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       "body .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       "body .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       "body .kp { color: #008000 } /* Keyword.Pseudo */\n",
       "body .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       "body .kt { color: #B00040 } /* Keyword.Type */\n",
       "body .m { color: #666666 } /* Literal.Number */\n",
       "body .s { color: #BA2121 } /* Literal.String */\n",
       "body .na { color: #7D9029 } /* Name.Attribute */\n",
       "body .nb { color: #008000 } /* Name.Builtin */\n",
       "body .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       "body .no { color: #880000 } /* Name.Constant */\n",
       "body .nd { color: #AA22FF } /* Name.Decorator */\n",
       "body .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       "body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       "body .nf { color: #0000FF } /* Name.Function */\n",
       "body .nl { color: #A0A000 } /* Name.Label */\n",
       "body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       "body .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       "body .nv { color: #19177C } /* Name.Variable */\n",
       "body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       "body .w { color: #bbbbbb } /* Text.Whitespace */\n",
       "body .mb { color: #666666 } /* Literal.Number.Bin */\n",
       "body .mf { color: #666666 } /* Literal.Number.Float */\n",
       "body .mh { color: #666666 } /* Literal.Number.Hex */\n",
       "body .mi { color: #666666 } /* Literal.Number.Integer */\n",
       "body .mo { color: #666666 } /* Literal.Number.Oct */\n",
       "body .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       "body .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       "body .sc { color: #BA2121 } /* Literal.String.Char */\n",
       "body .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       "body .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       "body .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       "body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       "body .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       "body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       "body .sx { color: #008000 } /* Literal.String.Other */\n",
       "body .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       "body .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       "body .ss { color: #19177C } /* Literal.String.Symbol */\n",
       "body .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       "body .fm { color: #0000FF } /* Name.Function.Magic */\n",
       "body .vc { color: #19177C } /* Name.Variable.Class */\n",
       "body .vg { color: #19177C } /* Name.Variable.Global */\n",
       "body .vi { color: #19177C } /* Name.Variable.Instance */\n",
       "body .vm { color: #19177C } /* Name.Variable.Magic */\n",
       "body .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "\n",
       "  </style>\n",
       "</head>\n",
       "<body>\n",
       "<h2></h2>\n",
       "\n",
       "<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">hill_climbing</span><span class=\"p\">(</span><span class=\"n\">problem</span><span class=\"p\">):</span>\n",
       "    <span class=\"sd\">&quot;&quot;&quot;From the initial node, keep choosing the neighbor with highest value,</span>\n",
       "<span class=\"sd\">    stopping when no neighbor is better. [Figure 4.2]&quot;&quot;&quot;</span>\n",
       "    <span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"n\">Node</span><span class=\"p\">(</span><span class=\"n\">problem</span><span class=\"o\">.</span><span class=\"n\">initial</span><span class=\"p\">)</span>\n",
       "    <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n",
       "        <span class=\"n\">neighbors</span> <span class=\"o\">=</span> <span class=\"n\">current</span><span class=\"o\">.</span><span class=\"n\">expand</span><span class=\"p\">(</span><span class=\"n\">problem</span><span class=\"p\">)</span>\n",
       "        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">neighbors</span><span class=\"p\">:</span>\n",
       "            <span class=\"k\">break</span>\n",
       "        <span class=\"n\">neighbor</span> <span class=\"o\">=</span> <span class=\"n\">argmax_random_tie</span><span class=\"p\">(</span><span class=\"n\">neighbors</span><span class=\"p\">,</span>\n",
       "                                     <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"k\">lambda</span> <span class=\"n\">node</span><span class=\"p\">:</span> <span class=\"n\">problem</span><span class=\"o\">.</span><span class=\"n\">value</span><span class=\"p\">(</span><span class=\"n\">node</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">))</span>\n",
       "        <span class=\"k\">if</span> <span class=\"n\">problem</span><span class=\"o\">.</span><span class=\"n\">value</span><span class=\"p\">(</span><span class=\"n\">neighbor</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">)</span> <span class=\"o\">&lt;=</span> <span class=\"n\">problem</span><span class=\"o\">.</span><span class=\"n\">value</span><span class=\"p\">(</span><span class=\"n\">current</span><span class=\"o\">.</span><span class=\"n\">state</span><span class=\"p\">):</span>\n",
       "            <span class=\"k\">break</span>\n",
       "        <span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"n\">neighbor</span>\n",
       "    <span class=\"k\">return</span> <span class=\"n\">current</span><span class=\"o\">.</span><span class=\"n\">state</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "psource(hill_climbing)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will find an approximate solution to the traveling salespersons problem using this algorithm.\n",
    "<br>\n",
    "We need to define a class for this problem.\n",
    "<br>\n",
    "`Problem` will be used as a base class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class TSP_problem(Problem):\n",
    "\n",
    "    \"\"\" subclass of Problem to define various functions \"\"\"\n",
    "\n",
    "    def two_opt(self, state):\n",
    "        \"\"\" Neighbour generating function for Traveling Salesman Problem \"\"\"\n",
    "        neighbour_state = state[:]\n",
    "        left = random.randint(0, len(neighbour_state) - 1)\n",
    "        right = random.randint(0, len(neighbour_state) - 1)\n",
    "        if left > right:\n",
    "            left, right = right, left\n",
    "        neighbour_state[left: right + 1] = reversed(neighbour_state[left: right + 1])\n",
    "        return neighbour_state\n",
    "\n",
    "    def actions(self, state):\n",
    "        \"\"\" action that can be excuted in given state \"\"\"\n",
    "        return [self.two_opt]\n",
    "\n",
    "    def result(self, state, action):\n",
    "        \"\"\"  result after applying the given action on the given state \"\"\"\n",
    "        return action(state)\n",
    "\n",
    "    def path_cost(self, c, state1, action, state2):\n",
    "        \"\"\" total distance for the Traveling Salesman to be covered if in state2  \"\"\"\n",
    "        cost = 0\n",
    "        for i in range(len(state2) - 1):\n",
    "            cost += distances[state2[i]][state2[i + 1]]\n",
    "        cost += distances[state2[0]][state2[-1]]\n",
    "        return cost\n",
    "\n",
    "    def value(self, state):\n",
    "        \"\"\" value of path cost given negative for the given state \"\"\"\n",
    "        return -1 * self.path_cost(None, None, None, state)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will use cities from the Romania map as our cities for this problem.\n",
    "<br>\n",
    "A list of all cities and a dictionary storing distances between them will be populated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['Arad', 'Bucharest', 'Craiova', 'Drobeta', 'Eforie', 'Fagaras', 'Giurgiu', 'Hirsova', 'Iasi', 'Lugoj', 'Mehadia', 'Neamt', 'Oradea', 'Pitesti', 'Rimnicu', 'Sibiu', 'Timisoara', 'Urziceni', 'Vaslui', 'Zerind']\n"
     ]
    }
   ],
   "source": [
    "distances = {}\n",
    "all_cities = []\n",
    "\n",
    "for city in romania_map.locations.keys():\n",
    "    distances[city] = {}\n",
    "    all_cities.append(city)\n",
    "    \n",
    "all_cities.sort()\n",
    "print(all_cities)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we need to populate the individual lists inside the dictionary with the manhattan distance between the cities."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "for name_1, coordinates_1 in romania_map.locations.items():\n",
    "        for name_2, coordinates_2 in romania_map.locations.items():\n",
    "            distances[name_1][name_2] = np.linalg.norm(\n",
    "                [coordinates_1[0] - coordinates_2[0], coordinates_1[1] - coordinates_2[1]])\n",
    "            distances[name_2][name_1] = np.linalg.norm(\n",
    "                [coordinates_1[0] - coordinates_2[0], coordinates_1[1] - coordinates_2[1]])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The way neighbours are chosen currently isn't suitable for the travelling salespersons problem.\n",
    "We need a neighboring state that is similar in total path distance to the current state.\n",
    "<br>\n",
    "We need to change the function that finds neighbors."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def hill_climbing(problem):\n",
    "    \n",
    "    \"\"\"From the initial node, keep choosing the neighbor with highest value,\n",
    "    stopping when no neighbor is better. [Figure 4.2]\"\"\"\n",
    "    \n",
    "    def find_neighbors(state, number_of_neighbors=100):\n",
    "        \"\"\" finds neighbors using two_opt method \"\"\"\n",
    "        \n",
    "        neighbors = []\n",
    "        \n",
    "        for i in range(number_of_neighbors):\n",
    "            new_state = problem.two_opt(state)\n",
    "            neighbors.append(Node(new_state))\n",
    "            state = new_state\n",
    "            \n",
    "        return neighbors\n",
    "\n",
    "    # as this is a stochastic algorithm, we will set a cap on the number of iterations\n",
    "    iterations = 10000\n",
    "    \n",
    "    current = Node(problem.initial)\n",
    "    while iterations:\n",
    "        neighbors = find_neighbors(current.state)\n",
    "        if not neighbors:\n",
    "            break\n",
    "        neighbor = argmax_random_tie(neighbors,\n",
    "                                     key=lambda node: problem.value(node.state))\n",
    "        if problem.value(neighbor.state) <= problem.value(current.state):\n",
    "            current.state = neighbor.state\n",
    "        iterations -= 1\n",
    "        \n",
    "    return current.state"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An instance of the TSP_problem class will be created."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "tsp = TSP_problem(all_cities)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now generate an approximate solution to the problem by calling `hill_climbing`.\n",
    "The results will vary a bit each time you run it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Fagaras',\n",
       " 'Neamt',\n",
       " 'Iasi',\n",
       " 'Vaslui',\n",
       " 'Hirsova',\n",
       " 'Eforie',\n",
       " 'Urziceni',\n",
       " 'Bucharest',\n",
       " 'Giurgiu',\n",
       " 'Pitesti',\n",
       " 'Craiova',\n",
       " 'Drobeta',\n",
       " 'Mehadia',\n",
       " 'Lugoj',\n",
       " 'Timisoara',\n",
       " 'Arad',\n",
       " 'Zerind',\n",
       " 'Oradea',\n",
       " 'Sibiu',\n",
       " 'Rimnicu']"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hill_climbing(tsp)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The solution looks like this.\n",
    "It is not difficult to see why this might be a good solution.\n",
    "<br>\n",
    "![title](images/hillclimb-tsp.png)"
   ]
  },
  {
   "cell_type": "markdown",
    "## GENETIC ALGORITHM\n",
    "\n",
    "Genetic algorithms (or GA) are inspired by natural evolution and are particularly useful in optimization and search problems with large state spaces.\n",
    "\n",
    "Given a problem, algorithms in the domain make use of a *population* of solutions (also called *states*), where each solution/state represents a feasible solution. At each iteration (often called *generation*), the population gets updated using methods inspired by biology and evolution, like *crossover*, *mutation* and *natural selection*."
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Overview\n",
    "\n",
    "A genetic algorithm works in the following way:\n",
    "\n",
    "1) Initialize random population.\n",
    "\n",
    "2) Calculate population fitness.\n",
    "\n",
    "3) Select individuals for mating.\n",
    "\n",
    "4) Mate selected individuals to produce new population.\n",
    "\n",
    "     * Random chance to mutate individuals.\n",
    "\n",
    "5) Repeat from step 2) until an individual is fit enough or the maximum number of iterations was reached."
    "### Glossary\n",
    "\n",
    "Before we continue, we will lay the basic terminology of the algorithm.\n",
    "\n",
    "* Individual/State: A list of elements (called *genes*) that represent possible solutions.\n",
    "* Population: The list of all the individuals/states.\n",
    "\n",
    "* Gene pool: The alphabet of possible values for an individual's genes.\n",
    "\n",
    "* Generation/Iteration: The number of times the population will be updated.\n",
    "\n",
    "* Fitness: An individual's score, calculated by a function specific to the problem."
    "### Crossover\n",
    "\n",
    "Two individuals/states can \"mate\" and produce one child. This offspring bears characteristics from both of its parents. There are many ways we can implement this crossover. Here we will take a look at the most common ones. Most other methods are variations of those below.\n",
    "\n",
    "* Point Crossover: The crossover occurs around one (or more) point. The parents get \"split\" at the chosen point or points and then get merged. In the example below we see two parents get split and merged at the 3rd digit, producing the following offspring after the crossover.\n",
    "\n",
    "![point crossover](images/point_crossover.png)\n",
    "\n",
    "* Uniform Crossover: This type of crossover chooses randomly the genes to get merged. Here the genes 1, 2 and 5 were chosen from the first parent, so the genes 3, 4 were added by the second parent.\n",
    "\n",
    "![uniform crossover](images/uniform_crossover.png)"
    "### Mutation\n",
    "\n",
    "When an offspring is produced, there is a chance it will mutate, having one (or more, depending on the implementation) of its genes altered.\n",
    "\n",
    "For example, let's say the new individual to undergo mutation is \"abcde\". Randomly we pick to change its third gene to 'z'. The individual now becomes \"abzde\" and is added to the population."
    "### Selection\n",
    "At each iteration, the fittest individuals are picked randomly to mate and produce offsprings. We measure an individual's fitness with a *fitness function*. That function depends on the given problem and it is used to score an individual. Usually the higher the better.\n",
    "The selection process is this:\n",
    "1) Individuals are scored by the fitness function.\n",
    "\n",
    "2) Individuals are picked randomly, according to their score (higher score means higher chance to get picked). Usually the formula to calculate the chance to pick an individual is the following (for population *P* and individual *i*):\n",
    "\n",
    "$$ chance(i) = \\dfrac{fitness(i)}{\\sum_{k \\, in \\, P}{fitness(k)}} $$"
    "### Implementation\n",
    "\n",
    "Below we look over the implementation of the algorithm in the `search` module.\n",
    "\n",
    "First the implementation of the main core of the algorithm:"
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n",
       "   \"http://www.w3.org/TR/html4/strict.dtd\">\n",
       "\n",
       "<html>\n",
       "<head>\n",
       "  <title></title>\n",
       "  <meta http-equiv=\"content-type\" content=\"text/html; charset=None\">\n",
       "  <style type=\"text/css\">\n",
       "td.linenos { background-color: #f0f0f0; padding-right: 10px; }\n",
       "span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
       "pre { line-height: 125%; }\n",
       "body .hll { background-color: #ffffcc }\n",
       "body  { background: #f8f8f8; }\n",
       "body .c { color: #408080; font-style: italic } /* Comment */\n",
       "body .err { border: 1px solid #FF0000 } /* Error */\n",
       "body .k { color: #008000; font-weight: bold } /* Keyword */\n",
       "body .o { color: #666666 } /* Operator */\n",
       "body .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       "body .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       "body .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       "body .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       "body .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       "body .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       "body .gd { color: #A00000 } /* Generic.Deleted */\n",
       "body .ge { font-style: italic } /* Generic.Emph */\n",
       "body .gr { color: #FF0000 } /* Generic.Error */\n",
       "body .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       "body .gi { color: #00A000 } /* Generic.Inserted */\n",
       "body .go { color: #888888 } /* Generic.Output */\n",
       "body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       "body .gs { font-weight: bold } /* Generic.Strong */\n",
       "body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       "body .gt { color: #0044DD } /* Generic.Traceback */\n",
       "body .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       "body .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       "body .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       "body .kp { color: #008000 } /* Keyword.Pseudo */\n",
       "body .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       "body .kt { color: #B00040 } /* Keyword.Type */\n",
       "body .m { color: #666666 } /* Literal.Number */\n",
       "body .s { color: #BA2121 } /* Literal.String */\n",
       "body .na { color: #7D9029 } /* Name.Attribute */\n",
       "body .nb { color: #008000 } /* Name.Builtin */\n",
       "body .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       "body .no { color: #880000 } /* Name.Constant */\n",
       "body .nd { color: #AA22FF } /* Name.Decorator */\n",
       "body .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       "body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       "body .nf { color: #0000FF } /* Name.Function */\n",
       "body .nl { color: #A0A000 } /* Name.Label */\n",
       "body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       "body .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       "body .nv { color: #19177C } /* Name.Variable */\n",
       "body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       "body .w { color: #bbbbbb } /* Text.Whitespace */\n",
       "body .mb { color: #666666 } /* Literal.Number.Bin */\n",
       "body .mf { color: #666666 } /* Literal.Number.Float */\n",
       "body .mh { color: #666666 } /* Literal.Number.Hex */\n",
       "body .mi { color: #666666 } /* Literal.Number.Integer */\n",
       "body .mo { color: #666666 } /* Literal.Number.Oct */\n",
       "body .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       "body .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       "body .sc { color: #BA2121 } /* Literal.String.Char */\n",
       "body .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       "body .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       "body .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       "body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       "body .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       "body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       "body .sx { color: #008000 } /* Literal.String.Other */\n",
       "body .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       "body .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       "body .ss { color: #19177C } /* Literal.String.Symbol */\n",
       "body .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       "body .fm { color: #0000FF } /* Name.Function.Magic */\n",
       "body .vc { color: #19177C } /* Name.Variable.Class */\n",
       "body .vg { color: #19177C } /* Name.Variable.Global */\n",
       "body .vi { color: #19177C } /* Name.Variable.Instance */\n",
       "body .vm { color: #19177C } /* Name.Variable.Magic */\n",
       "body .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "\n",
       "  </style>\n",
       "</head>\n",
       "<body>\n",
       "<h2></h2>\n",
       "\n",
       "<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">genetic_algorithm</span><span class=\"p\">(</span><span class=\"n\">population</span><span class=\"p\">,</span> <span class=\"n\">fitness_fn</span><span class=\"p\">,</span> <span class=\"n\">gene_pool</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">f_thres</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">ngen</span><span class=\"o\">=</span><span class=\"mi\">1000</span><span class=\"p\">,</span> <span class=\"n\">pmut</span><span class=\"o\">=</span><span class=\"mf\">0.1</span><span class=\"p\">):</span>\n",
       "    <span class=\"sd\">&quot;&quot;&quot;[Figure 4.8]&quot;&quot;&quot;</span>\n",
       "    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">ngen</span><span class=\"p\">):</span>\n",
       "        <span class=\"n\">population</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">mutate</span><span class=\"p\">(</span><span class=\"n\">recombine</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">select</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">population</span><span class=\"p\">,</span> <span class=\"n\">fitness_fn</span><span class=\"p\">)),</span> <span class=\"n\">gene_pool</span><span class=\"p\">,</span> <span class=\"n\">pmut</span><span class=\"p\">)</span>\n",
       "                      <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">population</span><span class=\"p\">))]</span>\n",
       "\n",
       "        <span class=\"n\">fittest_individual</span> <span class=\"o\">=</span> <span class=\"n\">fitness_threshold</span><span class=\"p\">(</span><span class=\"n\">fitness_fn</span><span class=\"p\">,</span> <span class=\"n\">f_thres</span><span class=\"p\">,</span> <span class=\"n\">population</span><span class=\"p\">)</span>\n",
       "        <span class=\"k\">if</span> <span class=\"n\">fittest_individual</span><span class=\"p\">:</span>\n",
       "            <span class=\"k\">return</span> <span class=\"n\">fittest_individual</span>\n",
       "\n",
       "\n",
       "    <span class=\"k\">return</span> <span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">population</span><span class=\"p\">,</span> <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"n\">fitness_fn</span><span class=\"p\">)</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "The algorithm takes the following input:\n",
    "\n",
    "* `population`: The initial population.\n",
    "\n",
    "* `fitness_fn`: The problem's fitness function.\n",
    "\n",
    "* `gene_pool`: The gene pool of the states/individuals. By default 0 and 1.\n",
    "* `f_thres`: The fitness threshold. If an individual reaches that score, iteration stops. By default 'None', which means the algorithm will not halt until the generations are ran.\n",
    "\n",
    "* `ngen`: The number of iterations/generations.\n",
    "\n",
    "* `pmut`: The probability of mutation.\n",
    "\n",
    "The algorithm gives as output the state with the largest score."
    "For each generation, the algorithm updates the population. First it calculates the fitnesses of the individuals, then it selects the most fit ones and finally crosses them over to produce offsprings. There is a chance that the offspring will be mutated, given by `pmut`. If at the end of the generation an individual meets the fitness threshold, the algorithm halts and returns that individual.\n",
    "\n",
    "The function of mating is accomplished by the method `recombine`:"
   "execution_count": 3,
2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n",
       "   \"http://www.w3.org/TR/html4/strict.dtd\">\n",
       "\n",
       "<html>\n",
       "<head>\n",
       "  <title></title>\n",
       "  <meta http-equiv=\"content-type\" content=\"text/html; charset=None\">\n",
       "  <style type=\"text/css\">\n",
       "td.linenos { background-color: #f0f0f0; padding-right: 10px; }\n",
       "span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
       "pre { line-height: 125%; }\n",
       "body .hll { background-color: #ffffcc }\n",
       "body  { background: #f8f8f8; }\n",
       "body .c { color: #408080; font-style: italic } /* Comment */\n",
       "body .err { border: 1px solid #FF0000 } /* Error */\n",
       "body .k { color: #008000; font-weight: bold } /* Keyword */\n",
       "body .o { color: #666666 } /* Operator */\n",
       "body .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       "body .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       "body .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       "body .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       "body .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       "body .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       "body .gd { color: #A00000 } /* Generic.Deleted */\n",
       "body .ge { font-style: italic } /* Generic.Emph */\n",
       "body .gr { color: #FF0000 } /* Generic.Error */\n",
       "body .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       "body .gi { color: #00A000 } /* Generic.Inserted */\n",
       "body .go { color: #888888 } /* Generic.Output */\n",
       "body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       "body .gs { font-weight: bold } /* Generic.Strong */\n",
       "body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       "body .gt { color: #0044DD } /* Generic.Traceback */\n",
       "body .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       "body .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       "body .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       "body .kp { color: #008000 } /* Keyword.Pseudo */\n",
       "body .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       "body .kt { color: #B00040 } /* Keyword.Type */\n",
       "body .m { color: #666666 } /* Literal.Number */\n",
       "body .s { color: #BA2121 } /* Literal.String */\n",
       "body .na { color: #7D9029 } /* Name.Attribute */\n",
       "body .nb { color: #008000 } /* Name.Builtin */\n",
       "body .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       "body .no { color: #880000 } /* Name.Constant */\n",
       "body .nd { color: #AA22FF } /* Name.Decorator */\n",
       "body .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       "body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       "body .nf { color: #0000FF } /* Name.Function */\n",
       "body .nl { color: #A0A000 } /* Name.Label */\n",
       "body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       "body .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       "body .nv { color: #19177C } /* Name.Variable */\n",
       "body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       "body .w { color: #bbbbbb } /* Text.Whitespace */\n",
       "body .mb { color: #666666 } /* Literal.Number.Bin */\n",
       "body .mf { color: #666666 } /* Literal.Number.Float */\n",
       "body .mh { color: #666666 } /* Literal.Number.Hex */\n",
       "body .mi { color: #666666 } /* Literal.Number.Integer */\n",
       "body .mo { color: #666666 } /* Literal.Number.Oct */\n",
       "body .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       "body .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       "body .sc { color: #BA2121 } /* Literal.String.Char */\n",
       "body .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       "body .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       "body .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       "body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       "body .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       "body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       "body .sx { color: #008000 } /* Literal.String.Other */\n",
       "body .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       "body .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       "body .ss { color: #19177C } /* Literal.String.Symbol */\n",
       "body .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       "body .fm { color: #0000FF } /* Name.Function.Magic */\n",
       "body .vc { color: #19177C } /* Name.Variable.Class */\n",
       "body .vg { color: #19177C } /* Name.Variable.Global */\n",
       "body .vi { color: #19177C } /* Name.Variable.Instance */\n",
       "body .vm { color: #19177C } /* Name.Variable.Magic */\n",
       "body .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "\n",
       "  </style>\n",
       "</head>\n",
       "<body>\n",
       "<h2></h2>\n",
       "\n",
       "<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">recombine</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>\n",
       "    <span class=\"n\">n</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">)</span>\n",
       "    <span class=\"n\">c</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">n</span><span class=\"p\">)</span>\n",
       "    <span class=\"k\">return</span> <span class=\"n\">x</span><span class=\"p\">[:</span><span class=\"n\">c</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">y</span><span class=\"p\">[</span><span class=\"n\">c</span><span class=\"p\">:]</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "psource(recombine)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The method picks at random a point and merges the parents (`x` and `y`) around it.\n",
    "\n",
    "The mutation is done in the method `mutate`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n",
       "   \"http://www.w3.org/TR/html4/strict.dtd\">\n",
       "\n",
       "<html>\n",
       "<head>\n",
       "  <title></title>\n",
       "  <meta http-equiv=\"content-type\" content=\"text/html; charset=None\">\n",
       "  <style type=\"text/css\">\n",
       "td.linenos { background-color: #f0f0f0; padding-right: 10px; }\n",
       "span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
       "pre { line-height: 125%; }\n",
       "body .hll { background-color: #ffffcc }\n",
       "body  { background: #f8f8f8; }\n",
       "body .c { color: #408080; font-style: italic } /* Comment */\n",
       "body .err { border: 1px solid #FF0000 } /* Error */\n",
       "body .k { color: #008000; font-weight: bold } /* Keyword */\n",
       "body .o { color: #666666 } /* Operator */\n",
       "body .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       "body .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       "body .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       "body .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       "body .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       "body .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       "body .gd { color: #A00000 } /* Generic.Deleted */\n",
       "body .ge { font-style: italic } /* Generic.Emph */\n",
       "body .gr { color: #FF0000 } /* Generic.Error */\n",
       "body .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       "body .gi { color: #00A000 } /* Generic.Inserted */\n",
       "body .go { color: #888888 } /* Generic.Output */\n",
       "body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       "body .gs { font-weight: bold } /* Generic.Strong */\n",
       "body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       "body .gt { color: #0044DD } /* Generic.Traceback */\n",
       "body .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       "body .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       "body .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       "body .kp { color: #008000 } /* Keyword.Pseudo */\n",
       "body .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       "body .kt { color: #B00040 } /* Keyword.Type */\n",
       "body .m { color: #666666 } /* Literal.Number */\n",
       "body .s { color: #BA2121 } /* Literal.String */\n",
       "body .na { color: #7D9029 } /* Name.Attribute */\n",
       "body .nb { color: #008000 } /* Name.Builtin */\n",
       "body .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       "body .no { color: #880000 } /* Name.Constant */\n",
       "body .nd { color: #AA22FF } /* Name.Decorator */\n",
       "body .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       "body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       "body .nf { color: #0000FF } /* Name.Function */\n",
       "body .nl { color: #A0A000 } /* Name.Label */\n",
       "body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       "body .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       "body .nv { color: #19177C } /* Name.Variable */\n",
       "body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       "body .w { color: #bbbbbb } /* Text.Whitespace */\n",
       "body .mb { color: #666666 } /* Literal.Number.Bin */\n",
       "body .mf { color: #666666 } /* Literal.Number.Float */\n",
       "body .mh { color: #666666 } /* Literal.Number.Hex */\n",
       "body .mi { color: #666666 } /* Literal.Number.Integer */\n",
       "body .mo { color: #666666 } /* Literal.Number.Oct */\n",
       "body .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       "body .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       "body .sc { color: #BA2121 } /* Literal.String.Char */\n",
       "body .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       "body .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       "body .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       "body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       "body .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       "body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       "body .sx { color: #008000 } /* Literal.String.Other */\n",
       "body .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       "body .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       "body .ss { color: #19177C } /* Literal.String.Symbol */\n",
       "body .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       "body .fm { color: #0000FF } /* Name.Function.Magic */\n",
       "body .vc { color: #19177C } /* Name.Variable.Class */\n",
       "body .vg { color: #19177C } /* Name.Variable.Global */\n",
       "body .vi { color: #19177C } /* Name.Variable.Instance */\n",
       "body .vm { color: #19177C } /* Name.Variable.Magic */\n",
       "body .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "\n",
       "  </style>\n",
       "</head>\n",
       "<body>\n",
       "<h2></h2>\n",
       "\n",
       "<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">mutate</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">gene_pool</span><span class=\"p\">,</span> <span class=\"n\">pmut</span><span class=\"p\">):</span>\n",
       "    <span class=\"k\">if</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">uniform</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">&gt;=</span> <span class=\"n\">pmut</span><span class=\"p\">:</span>\n",
       "        <span class=\"k\">return</span> <span class=\"n\">x</span>\n",
       "\n",
       "    <span class=\"n\">n</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">)</span>\n",
       "    <span class=\"n\">g</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">gene_pool</span><span class=\"p\">)</span>\n",
       "    <span class=\"n\">c</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">n</span><span class=\"p\">)</span>\n",
       "    <span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">g</span><span class=\"p\">)</span>\n",
       "\n",
       "    <span class=\"n\">new_gene</span> <span class=\"o\">=</span> <span class=\"n\">gene_pool</span><span class=\"p\">[</span><span class=\"n\">r</span><span class=\"p\">]</span>\n",
       "    <span class=\"k\">return</span> <span class=\"n\">x</span><span class=\"p\">[:</span><span class=\"n\">c</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"p\">[</span><span class=\"n\">new_gene</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">x</span><span class=\"p\">[</span><span class=\"n\">c</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">:]</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "psource(mutate)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We pick a gene in `x` to mutate and a gene from the gene pool to replace it with.\n",
    "\n",
    "To help initializing the population we have the helper function `init_population`\":"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n",
       "   \"http://www.w3.org/TR/html4/strict.dtd\">\n",
       "\n",
       "<html>\n",
       "<head>\n",
       "  <title></title>\n",
       "  <meta http-equiv=\"content-type\" content=\"text/html; charset=None\">\n",
       "  <style type=\"text/css\">\n",
       "td.linenos { background-color: #f0f0f0; padding-right: 10px; }\n",
       "span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
       "pre { line-height: 125%; }\n",
       "body .hll { background-color: #ffffcc }\n",
       "body  { background: #f8f8f8; }\n",
       "body .c { color: #408080; font-style: italic } /* Comment */\n",
       "body .err { border: 1px solid #FF0000 } /* Error */\n",
       "body .k { color: #008000; font-weight: bold } /* Keyword */\n",
       "body .o { color: #666666 } /* Operator */\n",
       "body .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       "body .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       "body .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       "body .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       "body .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       "body .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       "body .gd { color: #A00000 } /* Generic.Deleted */\n",
       "body .ge { font-style: italic } /* Generic.Emph */\n",
       "body .gr { color: #FF0000 } /* Generic.Error */\n",
       "body .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       "body .gi { color: #00A000 } /* Generic.Inserted */\n",
       "body .go { color: #888888 } /* Generic.Output */\n",
       "body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       "body .gs { font-weight: bold } /* Generic.Strong */\n",
       "body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       "body .gt { color: #0044DD } /* Generic.Traceback */\n",
       "body .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       "body .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       "body .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       "body .kp { color: #008000 } /* Keyword.Pseudo */\n",
       "body .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       "body .kt { color: #B00040 } /* Keyword.Type */\n",
       "body .m { color: #666666 } /* Literal.Number */\n",
       "body .s { color: #BA2121 } /* Literal.String */\n",
       "body .na { color: #7D9029 } /* Name.Attribute */\n",
       "body .nb { color: #008000 } /* Name.Builtin */\n",
       "body .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       "body .no { color: #880000 } /* Name.Constant */\n",
       "body .nd { color: #AA22FF } /* Name.Decorator */\n",
       "body .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       "body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       "body .nf { color: #0000FF } /* Name.Function */\n",
       "body .nl { color: #A0A000 } /* Name.Label */\n",
       "body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       "body .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       "body .nv { color: #19177C } /* Name.Variable */\n",
       "body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       "body .w { color: #bbbbbb } /* Text.Whitespace */\n",
       "body .mb { color: #666666 } /* Literal.Number.Bin */\n",
       "body .mf { color: #666666 } /* Literal.Number.Float */\n",
       "body .mh { color: #666666 } /* Literal.Number.Hex */\n",
       "body .mi { color: #666666 } /* Literal.Number.Integer */\n",
       "body .mo { color: #666666 } /* Literal.Number.Oct */\n",
       "body .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       "body .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       "body .sc { color: #BA2121 } /* Literal.String.Char */\n",
       "body .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       "body .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       "body .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       "body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       "body .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       "body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       "body .sx { color: #008000 } /* Literal.String.Other */\n",
       "body .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       "body .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       "body .ss { color: #19177C } /* Literal.String.Symbol */\n",
       "body .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       "body .fm { color: #0000FF } /* Name.Function.Magic */\n",
       "body .vc { color: #19177C } /* Name.Variable.Class */\n",
       "body .vg { color: #19177C } /* Name.Variable.Global */\n",
       "body .vi { color: #19177C } /* Name.Variable.Instance */\n",
       "body .vm { color: #19177C } /* Name.Variable.Magic */\n",
       "body .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "\n",
       "  </style>\n",
       "</head>\n",
       "<body>\n",
       "<h2></h2>\n",
       "\n",
       "<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">init_population</span><span class=\"p\">(</span><span class=\"n\">pop_number</span><span class=\"p\">,</span> <span class=\"n\">gene_pool</span><span class=\"p\">,</span> <span class=\"n\">state_length</span><span class=\"p\">):</span>\n",
       "    <span class=\"sd\">&quot;&quot;&quot;Initializes population for genetic algorithm</span>\n",
       "<span class=\"sd\">    pop_number  :  Number of individuals in population</span>\n",
       "<span class=\"sd\">    gene_pool   :  List of possible values for individuals</span>\n",
       "<span class=\"sd\">    state_length:  The length of each individual&quot;&quot;&quot;</span>\n",
       "    <span class=\"n\">g</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">gene_pool</span><span class=\"p\">)</span>\n",
       "    <span class=\"n\">population</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">pop_number</span><span class=\"p\">):</span>\n",
       "        <span class=\"n\">new_individual</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">gene_pool</span><span class=\"p\">[</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">g</span><span class=\"p\">)]</span> <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">state_length</span><span class=\"p\">)]</span>\n",
       "        <span class=\"n\">population</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_individual</span><span class=\"p\">)</span>\n",
       "\n",
       "    <span class=\"k\">return</span> <span class=\"n\">population</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "psource(init_population)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The function takes as input the number of individuals in the population, the gene pool and the length of each individual/state. It creates individuals with random genes and returns the population when done."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Explanation\n",
    "\n",
Robert Hönig's avatar
Robert Hönig a validé
    "Before we solve problems using the genetic algorithm, we will explain how to intuitively understand the algorithm using a trivial example.\n",
    "\n",
    "#### Generating Phrases\n",
    "\n",
    "In this problem, we use a genetic algorithm to generate a particular target phrase from a population of random strings. This is a classic example that helps build intuition about how to use this algorithm in other problems as well. Before we break the problem down, let us try to brute force the solution. Let us say that we want to generate the phrase \"genetic algorithm\". The phrase is 17 characters long. We can use any character from the 26 lowercase characters and the space character. To generate a random phrase of length 17, each space can be filled in 27 ways. So the total number of possible phrases is\n",
    "\n",
    "$$ 27^{17} = 2153693963075557766310747 $$\n",
    "\n",
    "which is a massive number. If we wanted to generate the phrase \"Genetic Algorithm\", we would also have to include all the 26 uppercase characters into consideration thereby increasing the sample space from 27 characters to 53 characters and the total number of possible phrases then would be\n",
    "\n",
    "$$ 53^{17} = 205442259656281392806087233013 $$\n",
    "\n",
    "If we wanted to include punctuations and numerals into the sample space, we would have further complicated an already impossible problem. Hence, brute forcing is not an option. Now we'll apply the genetic algorithm and see how it significantly reduces the search space. We essentially want to *evolve* our population of random strings so that they better approximate the target phrase as the number of generations increase. Genetic algorithms work on the principle of Darwinian Natural Selection according to which, there are three key concepts that need to be in place for evolution to happen. They are:\n",
    "\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "* **Heredity**: There must be a process in place by which children receive the properties of their parents. <br> \n",
    "For this particular problem, two strings from the population will be chosen as parents and will be split at a random index and recombined as described in the `recombine` function to create a child. This child string will then be added to the new generation.\n",
Anthony Marakis's avatar
Anthony Marakis a validé
    "\n",
    "\n",
    "* **Variation**: There must be a variety of traits present in the population or a means with which to introduce variation. <br>If there is no variation in the sample space, we might never reach the global optimum. To ensure that there is enough variation, we can initialize a large population, but this gets computationally expensive as the population gets larger. Hence, we often use another method called mutation. In this method, we randomly change one or more characters of some strings in the population based on a predefined probability value called the mutation rate or mutation probability as described in the `mutate` function. The mutation rate is usually kept quite low. A mutation rate of zero fails to introduce variation in the population and a high mutation rate (say 50%) is as good as a coin flip and the population fails to benefit from the previous recombinations. An optimum balance has to be maintained between population size and mutation rate so as to reduce the computational cost as well as have sufficient variation in the population.\n",
    "\n",
    "\n",
    "* **Selection**: There must be some mechanism by which some members of the population have the opportunity to be parents and pass down their genetic information and some do not. This is typically referred to as \"survival of the fittest\". <br>\n",
    "There has to be some way of determining which phrases in our population have a better chance of eventually evolving into the target phrase. This is done by introducing a fitness function that calculates how close the generated phrase is to the target phrase. The function will simply return a scalar value corresponding to the number of matching characters between the generated phrase and the target phrase."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Before solving the problem, we first need to define our target phrase."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "target = 'Genetic Algorithm'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "We then need to define our gene pool, i.e the elements which an individual from the population might comprise of. Here, the gene pool contains all uppercase and lowercase letters of the English alphabet and the space character."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# The ASCII values of uppercase characters ranges from 65 to 91\n",
    "u_case = [chr(x) for x in range(65, 91)]\n",
    "# The ASCII values of lowercase characters ranges from 97 to 123\n",
    "l_case = [chr(x) for x in range(97, 123)]\n",
    "\n",
    "gene_pool = []\n",
    "gene_pool.extend(u_case) # adds the uppercase list to the gene pool\n",
    "gene_pool.extend(l_case) # adds the lowercase list to the gene pool\n",
    "gene_pool.append(' ')    # adds the space character to the gene pool"
   ]
  },
  {
   "cell_type": "markdown",
    "We now need to define the maximum size of each population. Larger populations have more variation but are computationally more  expensive to run algorithms on."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "max_population = 100"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As our population is not very large, we can afford to keep a relatively large mutation rate."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "mutation_rate = 0.07 # 7%"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Great! Now, we need to define the most important metric for the genetic algorithm, i.e the fitness function. This will simply return the number of matching characters between the generated sample and the target phrase."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def fitness_fn(sample):\n",
    "    # initialize fitness to 0\n",
    "    fitness = 0\n",
    "    for i in range(len(sample)):\n",
    "        # increment fitness by 1 for every matching character\n",
    "        if sample[i] == target[i]:\n",
    "            fitness += 1\n",
    "    return fitness"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Before we run our genetic algorithm, we need to initialize a random population. We will use the `init_population` function to do this. We need to pass in the maximum population size, the gene pool and the length of each individual, which in this case will be the same as the length of the target phrase."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "population = init_population(max_population, gene_pool, len(target))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will now define how the individuals in the population should change as the number of generations increases. First, the `select` function will be run on the population to select *two* individuals with high fitness values. These will be the parents which will then be recombined using the `recombine` function to generate the child."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "parents = select(2, population, fitness_fn) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# The recombine function takes two parents as arguments, so we need to unpack the previous variable\n",
    "child = recombine(*parents)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we need to apply a mutation according to the mutation rate. We call the `mutate` function on the child with the gene pool and mutation rate as the additional arguments."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "child = mutate(child, gene_pool, mutation_rate)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The above lines can be condensed into\n",
    "`child = mutate(recombine(*select(2, population, fitness_fn)), gene_pool, mutation_rate)`\n",
    "\n",
    "And, we need to do this `for` every individual in the current population to generate the new population."
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "population = [mutate(recombine(*select(2, population, fitness_fn)), gene_pool, mutation_rate) for i in range(len(population))]"
    "The individual with the highest fitness can then be found using the `max` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "current_best = max(population, key=fitness_fn)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's print this out"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['j', 'F', 'm', 'F', 'N', 'i', 'c', 'v', 'm', 'j', 'V', 'o', 'd', 'r', 't', 'V', 'H']\n"
     ]
    }
   ],
   "source": [
    "print(current_best)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We see that this is a list of characters. This can be converted to a string using the join function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "jFmFNicvmjVodrtVH\n"
     ]
    }
   ],
   "source": [
    "current_best_string = ''.join(current_best)\n",
    "print(current_best_string)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We now need to define the conditions to terminate the algorithm. This can happen in two ways\n",
    "1. Termination after a predefined number of generations\n",
    "2. Termination when the fitness of the best individual of the current generation reaches a predefined threshold value.\n",
   "execution_count": 46,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "ngen = 1200 # maximum number of generations\n",
    "# we set the threshold fitness equal to the length of the target phrase\n",
    "# i.e the algorithm only terminates whne it has got all the characters correct \n",
    "# or it has completed 'ngen' number of generations\n",
    "f_thres = len(target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "To generate `ngen` number of generations, we run a `for` loop `ngen` number of times. After each generation, we calculate the fitness of the best individual of the generation and compare it to the value of `f_thres` using the `fitness_threshold` function. After every generation, we print out the best individual of the generation and the corresponding fitness value. Lets now write a function to do this."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def genetic_algorithm_stepwise(population, fitness_fn, gene_pool=[0, 1], f_thres=None, ngen=1200, pmut=0.1):\n",
    "    for generation in range(ngen):\n",
    "        population = [mutate(recombine(*select(2, population, fitness_fn)), gene_pool, pmut) for i in range(len(population))]\n",
    "        # stores the individual genome with the highest fitness in the current population\n",
    "        current_best = ''.join(max(population, key=fitness_fn))\n",
    "        print(f'Current best: {current_best}\\t\\tGeneration: {str(generation)}\\t\\tFitness: {fitness_fn(current_best)}\\r', end='')\n",
    "        \n",
    "        # compare the fitness of the current best individual to f_thres\n",
    "        fittest_individual = fitness_threshold(fitness_fn, f_thres, population)\n",
    "        \n",
    "        # if fitness is greater than or equal to f_thres, we terminate the algorithm\n",
    "        if fittest_individual:\n",
    "            return fittest_individual, generation\n",
    "    return max(population, key=fitness_fn) , generation       "
   ]
  },
  {
   "cell_type": "markdown",
    "The function defined above is essentially the same as the one defined in `search.py` with the added functionality of printing out the data of each generation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n",
       "   \"http://www.w3.org/TR/html4/strict.dtd\">\n",
       "\n",
       "<html>\n",
       "<head>\n",
       "  <title></title>\n",
       "  <meta http-equiv=\"content-type\" content=\"text/html; charset=None\">\n",
       "  <style type=\"text/css\">\n",
       "td.linenos { background-color: #f0f0f0; padding-right: 10px; }\n",
       "span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
       "pre { line-height: 125%; }\n",
       "body .hll { background-color: #ffffcc }\n",
       "body  { background: #f8f8f8; }\n",
       "body .c { color: #408080; font-style: italic } /* Comment */\n",
       "body .err { border: 1px solid #FF0000 } /* Error */\n",
       "body .k { color: #008000; font-weight: bold } /* Keyword */\n",
       "body .o { color: #666666 } /* Operator */\n",
       "body .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       "body .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       "body .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       "body .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       "body .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       "body .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       "body .gd { color: #A00000 } /* Generic.Deleted */\n",
       "body .ge { font-style: italic } /* Generic.Emph */\n",
       "body .gr { color: #FF0000 } /* Generic.Error */\n",
       "body .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       "body .gi { color: #00A000 } /* Generic.Inserted */\n",
       "body .go { color: #888888 } /* Generic.Output */\n",
       "body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       "body .gs { font-weight: bold } /* Generic.Strong */\n",
       "body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       "body .gt { color: #0044DD } /* Generic.Traceback */\n",
       "body .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       "body .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       "body .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       "body .kp { color: #008000 } /* Keyword.Pseudo */\n",
       "body .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       "body .kt { color: #B00040 } /* Keyword.Type */\n",
       "body .m { color: #666666 } /* Literal.Number */\n",
       "body .s { color: #BA2121 } /* Literal.String */\n",
       "body .na { color: #7D9029 } /* Name.Attribute */\n",
       "body .nb { color: #008000 } /* Name.Builtin */\n",
       "body .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       "body .no { color: #880000 } /* Name.Constant */\n",
       "body .nd { color: #AA22FF } /* Name.Decorator */\n",
       "body .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       "body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       "body .nf { color: #0000FF } /* Name.Function */\n",
       "body .nl { color: #A0A000 } /* Name.Label */\n",
       "body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       "body .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       "body .nv { color: #19177C } /* Name.Variable */\n",
       "body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       "body .w { color: #bbbbbb } /* Text.Whitespace */\n",
       "body .mb { color: #666666 } /* Literal.Number.Bin */\n",
       "body .mf { color: #666666 } /* Literal.Number.Float */\n",
       "body .mh { color: #666666 } /* Literal.Number.Hex */\n",
       "body .mi { color: #666666 } /* Literal.Number.Integer */\n",
       "body .mo { color: #666666 } /* Literal.Number.Oct */\n",
       "body .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       "body .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       "body .sc { color: #BA2121 } /* Literal.String.Char */\n",
       "body .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       "body .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       "body .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       "body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       "body .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       "body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       "body .sx { color: #008000 } /* Literal.String.Other */\n",
       "body .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       "body .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       "body .ss { color: #19177C } /* Literal.String.Symbol */\n",
       "body .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       "body .fm { color: #0000FF } /* Name.Function.Magic */\n",
       "body .vc { color: #19177C } /* Name.Variable.Class */\n",
       "body .vg { color: #19177C } /* Name.Variable.Global */\n",
       "body .vi { color: #19177C } /* Name.Variable.Instance */\n",
       "body .vm { color: #19177C } /* Name.Variable.Magic */\n",
       "body .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "\n",
       "  </style>\n",
       "</head>\n",
       "<body>\n",
       "<h2></h2>\n",
       "\n",
       "<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">genetic_algorithm</span><span class=\"p\">(</span><span class=\"n\">population</span><span class=\"p\">,</span> <span class=\"n\">fitness_fn</span><span class=\"p\">,</span> <span class=\"n\">gene_pool</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">f_thres</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">ngen</span><span class=\"o\">=</span><span class=\"mi\">1000</span><span class=\"p\">,</span> <span class=\"n\">pmut</span><span class=\"o\">=</span><span class=\"mf\">0.1</span><span class=\"p\">):</span>\n",
       "    <span class=\"sd\">&quot;&quot;&quot;[Figure 4.8]&quot;&quot;&quot;</span>\n",
       "    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">ngen</span><span class=\"p\">):</span>\n",
       "        <span class=\"n\">population</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">mutate</span><span class=\"p\">(</span><span class=\"n\">recombine</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">select</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">population</span><span class=\"p\">,</span> <span class=\"n\">fitness_fn</span><span class=\"p\">)),</span> <span class=\"n\">gene_pool</span><span class=\"p\">,</span> <span class=\"n\">pmut</span><span class=\"p\">)</span>\n",
       "                      <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">population</span><span class=\"p\">))]</span>\n",
       "\n",
       "        <span class=\"n\">fittest_individual</span> <span class=\"o\">=</span> <span class=\"n\">fitness_threshold</span><span class=\"p\">(</span><span class=\"n\">fitness_fn</span><span class=\"p\">,</span> <span class=\"n\">f_thres</span><span class=\"p\">,</span> <span class=\"n\">population</span><span class=\"p\">)</span>\n",
       "        <span class=\"k\">if</span> <span class=\"n\">fittest_individual</span><span class=\"p\">:</span>\n",
       "            <span class=\"k\">return</span> <span class=\"n\">fittest_individual</span>\n",
       "\n",
       "\n",
       "    <span class=\"k\">return</span> <span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">population</span><span class=\"p\">,</span> <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"n\">fitness_fn</span><span class=\"p\">)</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "psource(genetic_algorithm)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have defined all the required functions and variables. Let's now create a new population and test the function we wrote above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Current best: Genetic Algorithm\t\tGeneration: 472\t\tFitness: 17\r"
     ]
    }
   ],
   "source": [
    "population = init_population(max_population, gene_pool, len(target))\n",
    "solution, generations = genetic_algorithm_stepwise(population, fitness_fn, gene_pool, f_thres, ngen, mutation_rate)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The genetic algorithm was able to converge!\n",
    "We implore you to rerun the above cell and play around with `target, max_population, f_thres, ngen` etc parameters to get a better intuition of how the algorithm works. To summarize, if we can define the problem states in simple array format and if we can create a fitness function to gauge how good or bad our approximate solutions are, there is a high chance that we can get a satisfactory solution using a genetic algorithm. \n",
    "- There is also a better GUI version of this program `genetic_algorithm_example.py` in the GUI folder for you to play around with."
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Usage\n",
    "Below we give two example usages for the genetic algorithm, for a graph coloring problem and the 8 queens problem.\n",
    "#### Graph Coloring\n",
    "First we will take on the simpler problem of coloring a small graph with two colors. Before we do anything, let's imagine how a solution might look. First, we have to represent our colors. Say, 'R' for red and 'G' for green. These make up our gene pool. What of the individual solutions though? For that, we will look at our problem. We stated we have a graph. A graph has nodes and edges, and we want to color the nodes. Naturally, we want to store each node's color. If we have four nodes, we can store their colors in a list of genes, one for each node. A possible solution will then look like this: ['R', 'R', 'G', 'R']. In the general case, we will represent each solution with a list of chars ('R' and 'G'), with length the number of nodes.\n",
    "Next we need to come up with a fitness function that appropriately scores individuals. Again, we will look at the problem definition at hand. We want to color a graph. For a solution to be optimal, no edge should connect two nodes of the same color. How can we use this information to score a solution? A naive (and ineffective) approach would be to count the different colors in the string. So ['R', 'R', 'R', 'R'] has a score of 1 and ['R', 'R', 'G', 'G'] has a score of 2. Why that fitness function is not ideal though? Why, we forgot the information about the edges! The edges are pivotal to the problem and the above function only deals with node colors. We didn't use all the information at hand and ended up with an ineffective answer. How, then, can we use that information to our advantage?\n",
    "We said that the optimal solution will have all the edges connecting nodes of different color. So, to score a solution we can count how many edges are valid (aka connecting nodes of different color). That is a great fitness function!\n",
    "Let's jump into solving this problem using the `genetic_algorithm` function."
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "First we need to represent the graph. Since we mostly need information about edges, we will just store the edges. We will denote edges with capital letters and nodes with integers:"
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "edges = {\n",
    "    'A': [0, 1],\n",
    "    'B': [0, 3],\n",
    "    'C': [1, 2],\n",
    "    'D': [2, 3]\n",
    "}"
    "Edge 'A' connects nodes 0 and 1, edge 'B' connects nodes 0 and 3 etc.\n",
    "\n",
    "We already said our gene pool is 'R' and 'G', so we can jump right into initializing our population. Since we have only four nodes, `state_length` should be 4. For the number of individuals, we will try 8. We can increase this number if we need higher accuracy, but be careful! Larger populations need more computating power and take longer. You need to strike that sweet balance between accuracy and cost (the ultimate dilemma of the programmer!)."
   "execution_count": 7,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[['R', 'G', 'G', 'R'], ['R', 'G', 'R', 'R'], ['G', 'R', 'G', 'R'], ['R', 'G', 'R', 'G'], ['G', 'R', 'R', 'G'], ['G', 'R', 'G', 'R'], ['G', 'R', 'R', 'R'], ['R', 'G', 'G', 'G']]\n"
    "population = init_population(8, ['R', 'G'], 4)\n",
    "print(population)"
    "We created and printed the population. You can see that the genes in the individuals are random and there are 8 individuals each with 4 genes.\n",
    "Next we need to write our fitness function. We previously said we want the function to count how many edges are valid. So, given a coloring/individual `c`, we will do just that:"
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def fitness(c):\n",
    "    return sum(c[n1] != c[n2] for (n1, n2) in edges.values())"
    "Great! Now we will run the genetic algorithm and see what solution it gives."
   "execution_count": 9,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['R', 'G', 'R', 'G']\n"
    "solution = genetic_algorithm(population, fitness, gene_pool=['R', 'G'])\n",
    "print(solution)"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "The algorithm converged to a solution. Let's check its score:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n"
     ]
    }
   ],
   "source": [
    "print(fitness(solution))"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "The solution has a score of 4. Which means it is optimal, since we have exactly 4 edges in our graph, meaning all are valid!\n",
    "*NOTE: Because the algorithm is non-deterministic, there is a chance a different solution is given. It might even be wrong, if we are very unlucky!*"
    "#### Eight Queens\n",
    "\n",
    "Let's take a look at a more complicated problem.\n",
    "\n",
    "In the *Eight Queens* problem, we are tasked with placing eight queens on an 8x8 chessboard without any queen threatening the others (aka queens should not be in the same row, column or diagonal). In its general form the problem is defined as placing *N* queens in an NxN chessboard without any conflicts.\n",
    "\n",
    "First we need to think about the representation of each solution. We can go the naive route of representing the whole chessboard with the queens' placements on it. That is definitely one way to go about it, but for the purpose of this tutorial we will do something different. We have eight queens, so we will have a gene for each of them. The gene pool will be numbers from 0 to 7, for the different columns. The *position* of the gene in the state will denote the row the particular queen is placed in.\n",
    "\n",
    "For example, we can have the state \"03304577\". Here the first gene with a value of 0 means \"the queen at row 0 is placed at column 0\", for the second gene \"the queen at row 1 is placed at column 3\" and so forth.\n",
    "\n",
    "We now need to think about the fitness function. On the graph coloring problem we counted the valid edges. The same thought process can be applied here. Instead of edges though, we have positioning between queens. If two queens are not threatening each other, we say they are at a \"non-attacking\" positioning. We can, therefore, count how many such positionings are there.\n",
    "\n",
    "Let's dive right in and initialize our population:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0, 2, 7, 1, 7, 3, 2, 4], [2, 7, 5, 4, 4, 5, 2, 0], [7, 1, 6, 0, 1, 3, 0, 2], [0, 3, 6, 1, 3, 0, 5, 4], [0, 4, 6, 4, 7, 4, 1, 6]]\n"
    "population = init_population(100, range(8), 8)\n",
    "print(population[:5])"
    "We have a population of 100 and each individual has 8 genes. The gene pool is the integers from 0 to 7, in string form. Above you can see the first five individuals.\n",
    "\n",
    "Next we need to write our fitness function. Remember, queens threaten each other if they are at the same row, column or diagonal.\n",
    "Since positionings are mutual, we must take care not to count them twice. Therefore for each queen, we will only check for conflicts for the queens after her.\n",
    "\n",
    "A gene's value in an individual `q` denotes the queen's column, and the position of the gene denotes its row. We can check if the aforementioned values between two genes are the same. We also need to check for diagonals. A queen *a* is in the diagonal of another queen, *b*, if the difference of the rows between them is equal to either their difference in columns (for the diagonal on the right of *a*) or equal to the negative difference of their columns (for the left diagonal of *a*). Below is given the fitness function."
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def fitness(q):\n",
    "    non_attacking = 0\n",
    "    for row1 in range(len(q)):\n",
    "        for row2 in range(row1+1, len(q)):\n",
    "            col1 = int(q[row1])\n",
    "            col2 = int(q[row2])\n",
    "            row_diff = row1 - row2\n",
    "            col_diff = col1 - col2\n",
    "            if col1 != col2 and row_diff != col_diff and row_diff != -col_diff:\n",
    "                non_attacking += 1\n",
    "    return non_attacking"
    "Note that the best score achievable is 28. That is because for each queen we only check for the queens after her. For the first queen we check 7 other queens, for the second queen 6 others and so on. In short, the number of checks we make is the sum 7+6+5+...+1. Which is equal to 7\\*(7+1)/2 = 28.\n",
    "\n",
    "Because it is very hard and will take long to find a perfect solution, we will set the fitness threshold at 25. If we find an individual with a score greater or equal to that, we will halt. Let's see how the genetic algorithm will fare."
  {
   "cell_type": "code",
   "execution_count": 16,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[5, 0, 6, 3, 7, 4, 1, 3]\n",
      "26\n"
    "solution = genetic_algorithm(population, fitness, f_thres=25, gene_pool=range(8))\n",
    "print(solution)\n",
    "print(fitness(solution))"
    "Above you can see the solution and its fitness score, which should be no less than 25."
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "With that this tutorial on the genetic algorithm comes to an end. Hope you found this guide helpful!"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
Anthony Marakis's avatar
Anthony Marakis a validé
   "version": "3.6.3"
 "nbformat_minor": 1