planning.ipynb 184 ko
Newer Older
    "print(cakeProblem.goal_test())"
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It has now successfully achieved its goal i.e, to have and eat the cake."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One might wonder if the order of the actions matters for this problem.\n",
    "Let's see for ourselves."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "ename": "Exception",
     "evalue": "Action 'Bake(Cake)' pre-conditions not satisfied",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mException\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-39-b340f831489f>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      6\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0maction\u001b[0m \u001b[1;32min\u001b[0m \u001b[0msolution\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 7\u001b[1;33m     \u001b[0mcakeProblem\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mact\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maction\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;32m~\\Documents\\Python\\Aima\\aima-python\\planning.py\u001b[0m in \u001b[0;36mact\u001b[1;34m(self, action)\u001b[0m\n\u001b[0;32m     44\u001b[0m             \u001b[1;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Action '{}' not found\"\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maction_name\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     45\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mlist_action\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcheck_precond\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minit\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 46\u001b[1;33m             \u001b[1;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Action '{}' pre-conditions not satisfied\"\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maction\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     47\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minit\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mlist_action\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minit\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mclauses\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     48\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mException\u001b[0m: Action 'Bake(Cake)' pre-conditions not satisfied"
     ]
    }
   ],
   "source": [
    "cakeProblem = have_cake_and_eat_cake_too()\n",
    "\n",
    "solution = [expr('Bake(Cake)'),\n",
    "            expr('Eat(Cake)')]\n",
    "\n",
    "for action in solution:\n",
    "    cakeProblem.act(action)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It raises an exception.\n",
    "Indeed, according to the problem, we cannot bake a cake if we already have one.\n",
    "In planning terms, '~Have(Cake)' is a precondition to the action 'Bake(Cake)'.\n",
    "Hence, this solution is invalid."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## SOLVING PLANNING PROBLEMS\n",
    "----\n",
    "### GRAPHPLAN\n",
    "<br>\n",
    "The GraphPlan algorithm is a popular method of solving classical planning problems.\n",
    "Before we get into the details of the algorithm, let's look at a special data structure called **planning graph**, used to give better heuristic estimates and plays a key role in the GraphPlan algorithm."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Planning Graph\n",
    "A planning graph is a directed graph organized into levels. \n",
    "Each level contains information about the current state of the knowledge base and the possible state-action links to and from that level.\n",
    "The first level contains the initial state with nodes representing each fluent that holds in that level.\n",
    "This level has state-action links linking each state to valid actions in that state.\n",
    "Each action is linked to all its preconditions and its effect states.\n",
    "Based on these effects, the next level is constructed.\n",
    "The next level contains similarly structured information about the next state.\n",
    "In this way, the graph is expanded using state-action links till we reach a state where all the required goals hold true simultaneously.\n",
    "We can say that we have reached our goal if none of the goal states in the current level are mutually exclusive.\n",
    "This will be explained in detail later.\n",
    "<br>\n",
    "Planning graphs only work for propositional planning problems, hence we need to eliminate all variables by generating all possible substitutions.\n",
    "<br>\n",
    "For example, the planning graph of the `have_cake_and_eat_cake_too` problem might look like this\n",
    "![title](images/cake_graph.jpg)\n",
    "<br>\n",
    "The black lines indicate links between states and actions.\n",
    "<br>\n",
    "In every planning problem, we are allowed to carry out the `no-op` action, ie, we can choose no action for a particular state.\n",
    "These are called 'Persistence' actions and are represented in the graph by the small square boxes.\n",
    "In technical terms, a persistence action has effects same as its preconditions.\n",
    "This enables us to carry a state to the next level.\n",
    "<br>\n",
    "<br>\n",
    "The gray lines indicate mutual exclusivity.\n",
    "This means that the actions connected by a gray line cannot be taken together.\n",
    "Mutual exclusivity (mutex) occurs in the following cases:\n",
    "1. **Inconsistent effects**: One action negates the effect of the other. For example, _Eat(Cake)_ and the persistence of _Have(Cake)_ have inconsistent effects because they disagree on the effect _Have(Cake)_\n",
    "2. **Interference**: One of the effects of an action is the negation of a precondition of the other. For example, _Eat(Cake)_ interferes with the persistence of _Have(Cake)_ by negating its precondition.\n",
    "3. **Competing needs**: One of the preconditions of one action is mutually exclusive with a precondition of the other. For example, _Bake(Cake)_ and _Eat(Cake)_ are mutex because they compete on the value of the _Have(Cake)_ precondition."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the module, planning graphs have been implemented using two classes, `Level` which stores data for a particular level and `Graph` which connects multiple levels together.\n",
    "Let's look at the `Level` class."
   "execution_count": 40,
   "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\">Level</span><span class=\"p\">:</span>\n",
       "    <span class=\"sd\">&quot;&quot;&quot;</span>\n",
       "<span class=\"sd\">    Contains the state of the planning problem</span>\n",
       "<span class=\"sd\">    and exhaustive list of actions which use the</span>\n",
       "<span class=\"sd\">    states as pre-condition.</span>\n",
       "<span class=\"sd\">    &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\">kb</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Initializes variables to hold state and action details of a level&quot;&quot;&quot;</span>\n",
       "\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">kb</span> <span class=\"o\">=</span> <span class=\"n\">kb</span>\n",
       "        <span class=\"c1\"># current state</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_state</span> <span class=\"o\">=</span> <span class=\"n\">kb</span><span class=\"o\">.</span><span class=\"n\">clauses</span>\n",
       "        <span class=\"c1\"># current action to state link</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_action_links</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n",
       "        <span class=\"c1\"># current state to action link</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_state_links</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n",
       "        <span class=\"c1\"># current action to next state link</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_action_links</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n",
       "        <span class=\"c1\"># next state to current action link</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_state_links</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n",
       "        <span class=\"c1\"># mutually exclusive actions</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">mutex</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\">actions</span><span class=\"p\">,</span> <span class=\"n\">objects</span><span class=\"p\">):</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">build</span><span class=\"p\">(</span><span class=\"n\">actions</span><span class=\"p\">,</span> <span class=\"n\">objects</span><span class=\"p\">)</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">find_mutex</span><span class=\"p\">()</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">separate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">e</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Separates an iterable of elements into positive and negative parts&quot;&quot;&quot;</span>\n",
       "\n",
       "        <span class=\"n\">positive</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "        <span class=\"n\">negative</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "        <span class=\"k\">for</span> <span class=\"n\">clause</span> <span class=\"ow\">in</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n",
       "            <span class=\"k\">if</span> <span class=\"n\">clause</span><span class=\"o\">.</span><span class=\"n\">op</span><span class=\"p\">[:</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;Not&#39;</span><span class=\"p\">:</span>\n",
       "                <span class=\"n\">negative</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">clause</span><span class=\"p\">)</span>\n",
       "            <span class=\"k\">else</span><span class=\"p\">:</span>\n",
       "                <span class=\"n\">positive</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">clause</span><span class=\"p\">)</span>\n",
       "        <span class=\"k\">return</span> <span class=\"n\">positive</span><span class=\"p\">,</span> <span class=\"n\">negative</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">find_mutex</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Finds mutually exclusive actions&quot;&quot;&quot;</span>\n",
       "\n",
       "        <span class=\"c1\"># Inconsistent effects</span>\n",
       "        <span class=\"n\">pos_nsl</span><span class=\"p\">,</span> <span class=\"n\">neg_nsl</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">separate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_state_links</span><span class=\"p\">)</span>\n",
       "\n",
       "        <span class=\"k\">for</span> <span class=\"n\">negeff</span> <span class=\"ow\">in</span> <span class=\"n\">neg_nsl</span><span class=\"p\">:</span>\n",
       "            <span class=\"n\">new_negeff</span> <span class=\"o\">=</span> <span class=\"n\">Expr</span><span class=\"p\">(</span><span class=\"n\">negeff</span><span class=\"o\">.</span><span class=\"n\">op</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">:],</span> <span class=\"o\">*</span><span class=\"n\">negeff</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">)</span>\n",
       "            <span class=\"k\">for</span> <span class=\"n\">poseff</span> <span class=\"ow\">in</span> <span class=\"n\">pos_nsl</span><span class=\"p\">:</span>\n",
       "                <span class=\"k\">if</span> <span class=\"n\">new_negeff</span> <span class=\"o\">==</span> <span class=\"n\">poseff</span><span class=\"p\">:</span>\n",
       "                    <span class=\"k\">for</span> <span class=\"n\">a</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_state_links</span><span class=\"p\">[</span><span class=\"n\">poseff</span><span class=\"p\">]:</span>\n",
       "                        <span class=\"k\">for</span> <span class=\"n\">b</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_state_links</span><span class=\"p\">[</span><span class=\"n\">negeff</span><span class=\"p\">]:</span>\n",
       "                            <span class=\"k\">if</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\">not</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">mutex</span><span class=\"p\">:</span>\n",
       "                                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">mutex</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">({</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">})</span>\n",
       "\n",
       "        <span class=\"c1\"># Interference will be calculated with the last step</span>\n",
       "        <span class=\"n\">pos_csl</span><span class=\"p\">,</span> <span class=\"n\">neg_csl</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">separate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_state_links</span><span class=\"p\">)</span>\n",
       "\n",
       "        <span class=\"c1\"># Competing needs</span>\n",
       "        <span class=\"k\">for</span> <span class=\"n\">posprecond</span> <span class=\"ow\">in</span> <span class=\"n\">pos_csl</span><span class=\"p\">:</span>\n",
       "            <span class=\"k\">for</span> <span class=\"n\">negprecond</span> <span class=\"ow\">in</span> <span class=\"n\">neg_csl</span><span class=\"p\">:</span>\n",
       "                <span class=\"n\">new_negprecond</span> <span class=\"o\">=</span> <span class=\"n\">Expr</span><span class=\"p\">(</span><span class=\"n\">negprecond</span><span class=\"o\">.</span><span class=\"n\">op</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">:],</span> <span class=\"o\">*</span><span class=\"n\">negprecond</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">)</span>\n",
       "                <span class=\"k\">if</span> <span class=\"n\">new_negprecond</span> <span class=\"o\">==</span> <span class=\"n\">posprecond</span><span class=\"p\">:</span>\n",
       "                    <span class=\"k\">for</span> <span class=\"n\">a</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_state_links</span><span class=\"p\">[</span><span class=\"n\">posprecond</span><span class=\"p\">]:</span>\n",
       "                        <span class=\"k\">for</span> <span class=\"n\">b</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_state_links</span><span class=\"p\">[</span><span class=\"n\">negprecond</span><span class=\"p\">]:</span>\n",
       "                            <span class=\"k\">if</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\">not</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">mutex</span><span class=\"p\">:</span>\n",
       "                                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">mutex</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">({</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">})</span>\n",
       "\n",
       "        <span class=\"c1\"># Inconsistent support</span>\n",
       "        <span class=\"n\">state_mutex</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "        <span class=\"k\">for</span> <span class=\"n\">pair</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">mutex</span><span class=\"p\">:</span>\n",
       "            <span class=\"n\">next_state_0</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_action_links</span><span class=\"p\">[</span><span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">pair</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]]</span>\n",
       "            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">pair</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">2</span><span class=\"p\">:</span>\n",
       "                <span class=\"n\">next_state_1</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_action_links</span><span class=\"p\">[</span><span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">pair</span><span class=\"p\">)[</span><span class=\"mi\">1</span><span class=\"p\">]]</span>\n",
       "            <span class=\"k\">else</span><span class=\"p\">:</span>\n",
       "                <span class=\"n\">next_state_1</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_action_links</span><span class=\"p\">[</span><span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">pair</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]]</span>\n",
       "            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">next_state_0</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">next_state_1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">):</span>\n",
       "                <span class=\"n\">state_mutex</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">({</span><span class=\"n\">next_state_0</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">next_state_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]})</span>\n",
       "        \n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">mutex</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">mutex</span> <span class=\"o\">+</span> <span class=\"n\">state_mutex</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">actions</span><span class=\"p\">,</span> <span class=\"n\">objects</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Populates the lists and dictionaries containing the state action dependencies&quot;&quot;&quot;</span>\n",
       "\n",
       "        <span class=\"k\">for</span> <span class=\"n\">clause</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_state</span><span class=\"p\">:</span>\n",
       "            <span class=\"n\">p_expr</span> <span class=\"o\">=</span> <span class=\"n\">Expr</span><span class=\"p\">(</span><span class=\"s1\">&#39;P&#39;</span> <span class=\"o\">+</span> <span class=\"n\">clause</span><span class=\"o\">.</span><span class=\"n\">op</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">clause</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">)</span>\n",
       "            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_action_links</span><span class=\"p\">[</span><span class=\"n\">p_expr</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">clause</span><span class=\"p\">]</span>\n",
       "            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_action_links</span><span class=\"p\">[</span><span class=\"n\">p_expr</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">clause</span><span class=\"p\">]</span>\n",
       "            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_state_links</span><span class=\"p\">[</span><span class=\"n\">clause</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">p_expr</span><span class=\"p\">]</span>\n",
       "            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_state_links</span><span class=\"p\">[</span><span class=\"n\">clause</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">p_expr</span><span class=\"p\">]</span>\n",
       "\n",
       "        <span class=\"k\">for</span> <span class=\"n\">a</span> <span class=\"ow\">in</span> <span class=\"n\">actions</span><span class=\"p\">:</span>\n",
       "            <span class=\"n\">num_args</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">)</span>\n",
       "            <span class=\"n\">possible_args</span> <span class=\"o\">=</span> <span class=\"nb\">tuple</span><span class=\"p\">(</span><span class=\"n\">itertools</span><span class=\"o\">.</span><span class=\"n\">permutations</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">,</span> <span class=\"n\">num_args</span><span class=\"p\">))</span>\n",
       "\n",
       "            <span class=\"k\">for</span> <span class=\"n\">arg</span> <span class=\"ow\">in</span> <span class=\"n\">possible_args</span><span class=\"p\">:</span>\n",
       "                <span class=\"k\">if</span> <span class=\"n\">a</span><span class=\"o\">.</span><span class=\"n\">check_precond</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">kb</span><span class=\"p\">,</span> <span class=\"n\">arg</span><span class=\"p\">):</span>\n",
       "                    <span class=\"k\">for</span> <span class=\"n\">num</span><span class=\"p\">,</span> <span class=\"n\">symbol</span> <span class=\"ow\">in</span> <span class=\"nb\">enumerate</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">):</span>\n",
       "                        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">symbol</span><span class=\"o\">.</span><span class=\"n\">op</span><span class=\"o\">.</span><span class=\"n\">islower</span><span class=\"p\">():</span>\n",
       "                            <span class=\"n\">arg</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">arg</span><span class=\"p\">)</span>\n",
       "                            <span class=\"n\">arg</span><span class=\"p\">[</span><span class=\"n\">num</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">symbol</span>\n",
       "                            <span class=\"n\">arg</span> <span class=\"o\">=</span> <span class=\"nb\">tuple</span><span class=\"p\">(</span><span class=\"n\">arg</span><span class=\"p\">)</span>\n",
       "\n",
       "                    <span class=\"n\">new_action</span> <span class=\"o\">=</span> <span class=\"n\">a</span><span class=\"o\">.</span><span class=\"n\">substitute</span><span class=\"p\">(</span><span class=\"n\">Expr</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">a</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">),</span> <span class=\"n\">arg</span><span class=\"p\">)</span>\n",
       "                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_action_links</span><span class=\"p\">[</span><span class=\"n\">new_action</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "\n",
       "                    <span class=\"k\">for</span> <span class=\"n\">clause</span> <span class=\"ow\">in</span> <span class=\"n\">a</span><span class=\"o\">.</span><span class=\"n\">precond</span><span class=\"p\">:</span>\n",
       "                        <span class=\"n\">new_clause</span> <span class=\"o\">=</span> <span class=\"n\">a</span><span class=\"o\">.</span><span class=\"n\">substitute</span><span class=\"p\">(</span><span class=\"n\">clause</span><span class=\"p\">,</span> <span class=\"n\">arg</span><span class=\"p\">)</span>\n",
       "                        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_action_links</span><span class=\"p\">[</span><span class=\"n\">new_action</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_clause</span><span class=\"p\">)</span>\n",
       "                        <span class=\"k\">if</span> <span class=\"n\">new_clause</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_state_links</span><span class=\"p\">:</span>\n",
       "                            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_state_links</span><span class=\"p\">[</span><span class=\"n\">new_clause</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_action</span><span class=\"p\">)</span>\n",
       "                        <span class=\"k\">else</span><span class=\"p\">:</span>\n",
       "                            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">current_state_links</span><span class=\"p\">[</span><span class=\"n\">new_clause</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">new_action</span><span class=\"p\">]</span>\n",
       "                   \n",
       "                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_action_links</span><span class=\"p\">[</span><span class=\"n\">new_action</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "                    <span class=\"k\">for</span> <span class=\"n\">clause</span> <span class=\"ow\">in</span> <span class=\"n\">a</span><span class=\"o\">.</span><span class=\"n\">effect</span><span class=\"p\">:</span>\n",
       "                        <span class=\"n\">new_clause</span> <span class=\"o\">=</span> <span class=\"n\">a</span><span class=\"o\">.</span><span class=\"n\">substitute</span><span class=\"p\">(</span><span class=\"n\">clause</span><span class=\"p\">,</span> <span class=\"n\">arg</span><span class=\"p\">)</span>\n",
       "\n",
       "                        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_action_links</span><span class=\"p\">[</span><span class=\"n\">new_action</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_clause</span><span class=\"p\">)</span>\n",
       "                        <span class=\"k\">if</span> <span class=\"n\">new_clause</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_state_links</span><span class=\"p\">:</span>\n",
       "                            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_state_links</span><span class=\"p\">[</span><span class=\"n\">new_clause</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_action</span><span class=\"p\">)</span>\n",
       "                        <span class=\"k\">else</span><span class=\"p\">:</span>\n",
       "                            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_state_links</span><span class=\"p\">[</span><span class=\"n\">new_clause</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">new_action</span><span class=\"p\">]</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">perform_actions</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Performs the necessary actions and returns a new Level&quot;&quot;&quot;</span>\n",
       "\n",
       "        <span class=\"n\">new_kb</span> <span class=\"o\">=</span> <span class=\"n\">FolKB</span><span class=\"p\">(</span><span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next_state_links</span><span class=\"o\">.</span><span class=\"n\">keys</span><span class=\"p\">())))</span>\n",
       "        <span class=\"k\">return</span> <span class=\"n\">Level</span><span class=\"p\">(</span><span class=\"n\">new_kb</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(Level)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Each level stores the following data\n",
    "1. The current state of the level in `current_state`\n",
    "2. Links from an action to its preconditions in `current_action_links`\n",
    "3. Links from a state to the possible actions in that state in `current_state_links`\n",
    "4. Links from each action to its effects in `next_action_links`\n",
    "5. Links from each possible next state from each action in `next_state_links`. This stores the same information as the `current_action_links` of the next level.\n",
    "6. Mutex links in `mutex`.\n",
    "<br>\n",
    "<br>\n",
    "The `find_mutex` method finds the mutex links according to the points given above.\n",
    "<br>\n",
    "The `build` method populates the data structures storing the state and action information.\n",
    "Persistence actions for each clause in the current state are also defined here. \n",
    "The newly created persistence action has the same name as its state, prefixed with a 'P'."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's now look at the `Graph` class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "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\">Graph</span><span class=\"p\">:</span>\n",
       "    <span class=\"sd\">&quot;&quot;&quot;</span>\n",
       "<span class=\"sd\">    Contains levels of state and actions</span>\n",
       "<span class=\"sd\">    Used in graph planning algorithm to extract a solution</span>\n",
       "<span class=\"sd\">    &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\">pddl</span><span class=\"p\">):</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pddl</span> <span class=\"o\">=</span> <span class=\"n\">pddl</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">kb</span> <span class=\"o\">=</span> <span class=\"n\">FolKB</span><span class=\"p\">(</span><span class=\"n\">pddl</span><span class=\"o\">.</span><span class=\"n\">init</span><span class=\"p\">)</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">levels</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">Level</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">kb</span><span class=\"p\">)]</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">arg</span> <span class=\"k\">for</span> <span class=\"n\">clause</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">kb</span><span class=\"o\">.</span><span class=\"n\">clauses</span> <span class=\"k\">for</span> <span class=\"n\">arg</span> <span class=\"ow\">in</span> <span class=\"n\">clause</span><span class=\"o\">.</span><span class=\"n\">args</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>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">expand_graph</span><span class=\"p\">()</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">expand_graph</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Expands the graph by a level&quot;&quot;&quot;</span>\n",
       "\n",
       "        <span class=\"n\">last_level</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">levels</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n",
       "        <span class=\"n\">last_level</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pddl</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\">objects</span><span class=\"p\">)</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">levels</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">last_level</span><span class=\"o\">.</span><span class=\"n\">perform_actions</span><span class=\"p\">())</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">non_mutex_goals</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">goals</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Checks whether the goals are mutually exclusive&quot;&quot;&quot;</span>\n",
       "\n",
       "        <span class=\"n\">goal_perm</span> <span class=\"o\">=</span> <span class=\"n\">itertools</span><span class=\"o\">.</span><span class=\"n\">combinations</span><span class=\"p\">(</span><span class=\"n\">goals</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n",
       "        <span class=\"k\">for</span> <span class=\"n\">g</span> <span class=\"ow\">in</span> <span class=\"n\">goal_perm</span><span class=\"p\">:</span>\n",
       "            <span class=\"k\">if</span> <span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">g</span><span class=\"p\">)</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">levels</span><span class=\"p\">[</span><span class=\"n\">index</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">mutex</span><span class=\"p\">:</span>\n",
       "                <span class=\"k\">return</span> <span class=\"bp\">False</span>\n",
       "        <span class=\"k\">return</span> <span class=\"bp\">True</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    "psource(Graph)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The class stores a problem definition in `pddl`, \n",
    "a knowledge base in `kb`, \n",
    "a list of `Level` objects in `levels` and \n",
    "all the possible arguments found in the initial state of the problem in `objects`.\n",
    "<br>\n",
    "The `expand_graph` method generates a new level of the graph.\n",
    "This method is invoked when the goal conditions haven't been met in the current level or the actions that lead to it are mutually exclusive.\n",
    "The `non_mutex_goals` method checks whether the goals in the current state are mutually exclusive.\n",
    "<br>\n",
    "<br>\n",
    "Using these two classes, we can define a planning graph which can either be used to provide reliable heuristics for planning problems or used in the `GraphPlan` algorithm.\n",
    "<br>\n",
    "Let's have a look at the `GraphPlan` class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "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\">GraphPlan</span><span class=\"p\">:</span>\n",
       "    <span class=\"sd\">&quot;&quot;&quot;</span>\n",
       "<span class=\"sd\">    Class for formulation GraphPlan algorithm</span>\n",
       "<span class=\"sd\">    Constructs a graph of state and action space</span>\n",
       "<span class=\"sd\">    Returns solution for the planning problem</span>\n",
       "<span class=\"sd\">    &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\">pddl</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><span class=\"p\">(</span><span class=\"n\">pddl</span><span class=\"p\">)</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nogoods</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">solution</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">check_leveloff</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Checks if the graph has levelled off&quot;&quot;&quot;</span>\n",
       "\n",
       "        <span class=\"n\">check</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"nb\">set</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\">levels</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">current_state</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"nb\">set</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\">levels</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">current_state</span><span class=\"p\">))</span>\n",
       "\n",
       "        <span class=\"k\">if</span> <span class=\"n\">check</span><span class=\"p\">:</span>\n",
       "            <span class=\"k\">return</span> <span class=\"bp\">True</span>\n",
       "\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">extract_solution</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">goals</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">):</span>\n",
       "        <span class=\"sd\">&quot;&quot;&quot;Extracts the solution&quot;&quot;&quot;</span>\n",
       "\n",
       "        <span class=\"n\">level</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">graph</span><span class=\"o\">.</span><span class=\"n\">levels</span><span class=\"p\">[</span><span class=\"n\">index</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\">graph</span><span class=\"o\">.</span><span class=\"n\">non_mutex_goals</span><span class=\"p\">(</span><span class=\"n\">goals</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">):</span>\n",
       "            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nogoods</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">((</span><span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">goals</span><span class=\"p\">))</span>\n",
       "            <span class=\"k\">return</span>\n",
       "\n",
       "        <span class=\"n\">level</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">graph</span><span class=\"o\">.</span><span class=\"n\">levels</span><span class=\"p\">[</span><span class=\"n\">index</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">]</span>    \n",
       "\n",
       "        <span class=\"c1\"># Create all combinations of actions that satisfy the goal    </span>\n",
       "        <span class=\"n\">actions</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "        <span class=\"k\">for</span> <span class=\"n\">goal</span> <span class=\"ow\">in</span> <span class=\"n\">goals</span><span class=\"p\">:</span>\n",
       "            <span class=\"n\">actions</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"o\">.</span><span class=\"n\">next_state_links</span><span class=\"p\">[</span><span class=\"n\">goal</span><span class=\"p\">])</span>    \n",
       "\n",
       "        <span class=\"n\">all_actions</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">itertools</span><span class=\"o\">.</span><span class=\"n\">product</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">actions</span><span class=\"p\">))</span>    \n",
       "\n",
       "        <span class=\"c1\"># Filter out non-mutex actions</span>\n",
       "        <span class=\"n\">non_mutex_actions</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>    \n",
       "        <span class=\"k\">for</span> <span class=\"n\">action_tuple</span> <span class=\"ow\">in</span> <span class=\"n\">all_actions</span><span class=\"p\">:</span>\n",
       "            <span class=\"n\">action_pairs</span> <span class=\"o\">=</span> <span class=\"n\">itertools</span><span class=\"o\">.</span><span class=\"n\">combinations</span><span class=\"p\">(</span><span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">action_tuple</span><span class=\"p\">)),</span> <span class=\"mi\">2</span><span class=\"p\">)</span>        \n",
       "            <span class=\"n\">non_mutex_actions</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">action_tuple</span><span class=\"p\">)))</span>        \n",
       "            <span class=\"k\">for</span> <span class=\"n\">pair</span> <span class=\"ow\">in</span> <span class=\"n\">action_pairs</span><span class=\"p\">:</span>            \n",
       "                <span class=\"k\">if</span> <span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">pair</span><span class=\"p\">)</span> <span class=\"ow\">in</span> <span class=\"n\">level</span><span class=\"o\">.</span><span class=\"n\">mutex</span><span class=\"p\">:</span>\n",
       "                    <span class=\"n\">non_mutex_actions</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n",
       "                    <span class=\"k\">break</span>\n",
       "    \n",
       "\n",
       "        <span class=\"c1\"># Recursion</span>\n",
       "        <span class=\"k\">for</span> <span class=\"n\">action_list</span> <span class=\"ow\">in</span> <span class=\"n\">non_mutex_actions</span><span class=\"p\">:</span>        \n",
       "            <span class=\"k\">if</span> <span class=\"p\">[</span><span class=\"n\">action_list</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">]</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">solution</span><span class=\"p\">:</span>\n",
       "                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">solution</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">([</span><span class=\"n\">action_list</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">])</span>\n",
       "\n",
       "                <span class=\"n\">new_goals</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "                <span class=\"k\">for</span> <span class=\"n\">act</span> <span class=\"ow\">in</span> <span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">action_list</span><span class=\"p\">):</span>                \n",
       "                    <span class=\"k\">if</span> <span class=\"n\">act</span> <span class=\"ow\">in</span> <span class=\"n\">level</span><span class=\"o\">.</span><span class=\"n\">current_action_links</span><span class=\"p\">:</span>\n",
       "                        <span class=\"n\">new_goals</span> <span class=\"o\">=</span> <span class=\"n\">new_goals</span> <span class=\"o\">+</span> <span class=\"n\">level</span><span class=\"o\">.</span><span class=\"n\">current_action_links</span><span class=\"p\">[</span><span class=\"n\">act</span><span class=\"p\">]</span>\n",
       "\n",
       "                <span class=\"k\">if</span> <span class=\"nb\">abs</span><span class=\"p\">(</span><span class=\"n\">index</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">==</span> <span class=\"nb\">len</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\">levels</span><span class=\"p\">):</span>\n",
       "                    <span class=\"k\">return</span>\n",
       "                <span class=\"k\">elif</span> <span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">new_goals</span><span class=\"p\">)</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nogoods</span><span class=\"p\">:</span>\n",
       "                    <span class=\"k\">return</span>\n",
       "                <span class=\"k\">else</span><span class=\"p\">:</span>\n",
       "                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">extract_solution</span><span class=\"p\">(</span><span class=\"n\">new_goals</span><span class=\"p\">,</span> <span class=\"n\">index</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n",
       "\n",
       "        <span class=\"c1\"># Level-Order multiple solutions</span>\n",
       "        <span class=\"n\">solution</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n",
       "        <span class=\"k\">for</span> <span class=\"n\">item</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">solution</span><span class=\"p\">:</span>\n",
       "            <span class=\"k\">if</span> <span class=\"n\">item</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">:</span>\n",
       "                <span class=\"n\">solution</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">([])</span>\n",
       "                <span class=\"n\">solution</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">item</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n",
       "            <span class=\"k\">else</span><span class=\"p\">:</span>\n",
       "                <span class=\"n\">solution</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">item</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n",
       "\n",
       "        <span class=\"k\">for</span> <span class=\"n\">num</span><span class=\"p\">,</span> <span class=\"n\">item</span> <span class=\"ow\">in</span> <span class=\"nb\">enumerate</span><span class=\"p\">(</span><span class=\"n\">solution</span><span class=\"p\">):</span>\n",
       "            <span class=\"n\">item</span><span class=\"o\">.</span><span class=\"n\">reverse</span><span class=\"p\">()</span>\n",
       "            <span class=\"n\">solution</span><span class=\"p\">[</span><span class=\"n\">num</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">item</span>\n",
       "\n",
       "        <span class=\"k\">return</span> <span class=\"n\">solution</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "psource(GraphPlan)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Given a planning problem defined as a PDDL, `GraphPlan` creates a planning graph stored in `graph` and expands it till it reaches a state where all its required goals are present simultaneously without mutual exclusivity.\n",
    "<br>\n",
    "Once a goal is found, `extract_solution` is called.\n",
    "This method recursively finds the path to a solution given a planning graph.\n",
    "In the case where `extract_solution` fails to find a solution for a set of goals as a given level, we record the `(level, goals)` pair as a **no-good**.\n",
    "Whenever `extract_solution` is called again with the same level and goals, we can find the recorded no-good and immediately return failure rather than searching again. \n",
    "No-goods are also used in the termination test.\n",
    "<br>\n",
    "The `check_leveloff` method checks if the planning graph for the problem has **levelled-off**, ie, it has the same states, actions and mutex pairs as the previous level.\n",
    "If the graph has already levelled off and we haven't found a solution, there is no point expanding the graph, as it won't lead to anything new.\n",
    "In such a case, we can declare that the planning problem is unsolvable with the given constraints.\n",
    "<br>\n",
    "<br>\n",
    "To summarize, the `GraphPlan` algorithm calls `expand_graph` and tests whether it has reached the goal and if the goals are non-mutex.\n",
    "<br>\n",
    "If so, `extract_solution` is invoked which recursively reconstructs the solution from the planning graph.\n",
    "<br>\n",
    "If not, then we check if our graph has levelled off and continue if it hasn't."
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's solve a few planning problems that we had defined earlier."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Air cargo problem:\n",
    "<br>\n",
    "In accordance with the summary above, we have defined a helper function to carry out `GraphPlan` on the `air_cargo` problem.\n",
    "The function is pretty straightforward.\n",
    "Let's have a look."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "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\">air_cargo_graphplan</span><span class=\"p\">():</span>\n",
       "    <span class=\"sd\">&quot;&quot;&quot;Solves the air cargo problem using GraphPlan&quot;&quot;&quot;</span>\n",
       "    <span class=\"n\">pddl</span> <span class=\"o\">=</span> <span class=\"n\">air_cargo</span><span class=\"p\">()</span>\n",
       "    <span class=\"n\">graphplan</span> <span class=\"o\">=</span> <span class=\"n\">GraphPlan</span><span class=\"p\">(</span><span class=\"n\">pddl</span><span class=\"p\">)</span>\n",
       "    <span class=\"k\">def</span> <span class=\"nf\">goal_test</span><span class=\"p\">(</span><span class=\"n\">kb</span><span class=\"p\">,</span> <span class=\"n\">goals</span><span class=\"p\">):</span>\n",
       "        <span class=\"k\">return</span> <span class=\"nb\">all</span><span class=\"p\">(</span><span class=\"n\">kb</span><span class=\"o\">.</span><span class=\"n\">ask</span><span class=\"p\">(</span><span class=\"n\">q</span><span class=\"p\">)</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"bp\">False</span> <span class=\"k\">for</span> <span class=\"n\">q</span> <span class=\"ow\">in</span> <span class=\"n\">goals</span><span class=\"p\">)</span>\n",
       "    <span class=\"n\">goals</span> <span class=\"o\">=</span> <span class=\"n\">expr</span><span class=\"p\">(</span><span class=\"s1\">&#39;At(C1, JFK), At(C2, SFO)&#39;</span><span class=\"p\">)</span>\n",
       "    <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n",
       "        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">goal_test</span><span class=\"p\">(</span><span class=\"n\">graphplan</span><span class=\"o\">.</span><span class=\"n\">graph</span><span class=\"o\">.</span><span class=\"n\">levels</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">kb</span><span class=\"p\">,</span> <span class=\"n\">goals</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">graphplan</span><span class=\"o\">.</span><span class=\"n\">graph</span><span class=\"o\">.</span><span class=\"n\">non_mutex_goals</span><span class=\"p\">(</span><span class=\"n\">goals</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)):</span>\n",
       "            <span class=\"n\">solution</span> <span class=\"o\">=</span> <span class=\"n\">graphplan</span><span class=\"o\">.</span><span class=\"n\">extract_solution</span><span class=\"p\">(</span><span class=\"n\">goals</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n",
       "            <span class=\"k\">if</span> <span class=\"n\">solution</span><span class=\"p\">:</span>\n",
       "                <span class=\"k\">return</span> <span class=\"n\">solution</span>\n",
       "        <span class=\"n\">graphplan</span><span class=\"o\">.</span><span class=\"n\">graph</span><span class=\"o\">.</span><span class=\"n\">expand_graph</span><span class=\"p\">()</span>\n",
       "        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">graphplan</span><span class=\"o\">.</span><span class=\"n\">graph</span><span class=\"o\">.</span><span class=\"n\">levels</span><span class=\"p\">)</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">2</span> <span class=\"ow\">and</span> <span class=\"n\">graphplan</span><span class=\"o\">.</span><span class=\"n\">check_leveloff</span><span class=\"p\">():</span>\n",
       "            <span class=\"k\">return</span> <span class=\"bp\">None</span>\n",
       "</pre></div>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "psource(air_cargo_graphplan)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's instantiate the problem and find a solution using this helper function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[[PCargo(C2),\n",
       "   Load(C2, P2, JFK),\n",
       "   PPlane(P2),\n",
       "   Load(C1, P1, SFO),\n",
       "   Fly(P1, SFO, JFK),\n",
       "   PAirport(SFO),\n",
       "   PAirport(JFK),\n",
       "   PPlane(P1),\n",
       "   PCargo(C1),\n",
       "   Fly(P2, JFK, SFO)],\n",
       "  [Unload(C2, P2, SFO), Unload(C1, P1, JFK)]]]"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "air_cargo = air_cargo_graphplan()\n",
    "air_cargo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Each element in the solution is a valid action.\n",
    "The solution is separated into lists for each level.\n",
    "The actions prefixed with a 'P' are persistence actions and can be ignored.\n",
    "They simply carry certain states forward.\n",
    "We have another helper function `linearize` that presents the solution in a more readable format, much like a total-order planner."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Load(C2, P2, JFK),\n",
       " Load(C1, P1, SFO),\n",
       " Fly(P1, SFO, JFK),\n",
       " Fly(P2, JFK, SFO),\n",
       " Unload(C2, P2, SFO),\n",
       " Unload(C1, P1, JFK)]"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    "linearize(air_cargo)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Indeed, this is a correct solution.\n",
    "<br>\n",
    "There are similar helper functions for some other planning problems.\n",
    "<br>\n",
    "Lets' try solving the spare tire problem."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Remove(Flat, Axle), Remove(Spare, Trunk), PutOn(Spare, Axle)]"
      ]
     },