diff --git a/logic_programming/1_IntroProlog.pdf b/logic_programming/1_IntroProlog.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..971619340373ee1e712a6a6c33d1fecff49ff8be
Binary files /dev/null and b/logic_programming/1_IntroProlog.pdf differ
diff --git a/logic_programming/2_IntroProlog.ipynb b/logic_programming/2_IntroProlog.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..aa66247f5753275ebfd488269c6ff2d7456fb8e0
--- /dev/null
+++ b/logic_programming/2_IntroProlog.ipynb
@@ -0,0 +1,3737 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "7359298e-63ac-4080-9139-aa90c8043b2a",
+   "metadata": {},
+   "source": [
+    "# A more systematic introduction to Prolog"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "49fd5211",
+   "metadata": {},
+   "source": [
+    "### Propositions\n",
+    "Prolog programs consist of <b>clauses</b>.\n",
+    "A clause is always terminated by a dot (```.```).\n",
+    "Propositions start with a lower case letter or you can use quotes to use (almost) arbitrary strings as propositions.\n",
+    "The simplest clauses are facts. Here we define three propositions to be true, for the last two we use quotes:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 47,
+   "id": "93e05f7b-a91c-4262-861e-a399e094b710",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:rains/0 were retracted (click to expand)</summary><pre>:- dynamic rains/0.\n",
+       "\n",
+       "rains.\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:rains/0 were retracted:\n",
+       ":- dynamic rains/0.\n",
+       "\n",
+       "rains.\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:rains/0\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:I am not wearing a hat/0 were retracted (click to expand)</summary><pre>:- dynamic'I am not wearing a hat'/0.\n",
+       "\n",
+       "'I am not wearing a hat'.\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:I am not wearing a hat/0 were retracted:\n",
+       ":- dynamic'I am not wearing a hat'/0.\n",
+       "\n",
+       "'I am not wearing a hat'.\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:I am not wearing a hat/0\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:The sun is shining/0 were retracted (click to expand)</summary><pre>:- dynamic'The sun is shining'/0.\n",
+       "\n",
+       "'The sun is shining'.\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:The sun is shining/0 were retracted:\n",
+       ":- dynamic'The sun is shining'/0.\n",
+       "\n",
+       "'The sun is shining'.\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:The sun is shining/0\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:beach/0 were retracted (click to expand)</summary><pre>:- dynamic beach/0.\n",
+       "\n",
+       "beach :-\n",
+       "    fail.\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:beach/0 were retracted:\n",
+       ":- dynamic beach/0.\n",
+       "\n",
+       "beach :-\n",
+       "    fail.\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:beach/0\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "rains.\n",
+    "'I am not wearing a hat'.\n",
+    "'The sun is shining'.\n",
+    "beach :- fail."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b05ae74b",
+   "metadata": {},
+   "source": [
+    "We can now ask the Prolog system whether the sun is shining:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "14013336",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1;31mfalse"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- beach."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 49,
+   "id": "20b05b2c",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?-'The sun is shining'."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "50c188fa",
+   "metadata": {},
+   "source": [
+    "More complicated clauses make use of the implication operator ```:-```. They are also called rules. Logically they stipulate that the left-hand side of the clause must be true if the right-hand side is true. The right-hand side can contain multiple propositions separated by commas. The comma can be read as a logical conjunction (and)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 50,
+   "id": "2b8b84a0",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:carry_umbrella/0 were retracted (click to expand)</summary><pre>:- dynamic carry_umbrella/0.\n",
+       "\n",
+       "carry_umbrella :-\n",
+       "    rains,\n",
+       "    'I am not wearing a hat'.\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:carry_umbrella/0 were retracted:\n",
+       ":- dynamic carry_umbrella/0.\n",
+       "\n",
+       "carry_umbrella :-\n",
+       "    rains,\n",
+       "    'I am not wearing a hat'.\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:carry_umbrella/0\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:rainbow/0 were retracted (click to expand)</summary><pre>:- dynamic rainbow/0.\n",
+       "\n",
+       "rainbow :-\n",
+       "    rains,\n",
+       "    'The sun is shining'.\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:rainbow/0 were retracted:\n",
+       ":- dynamic rainbow/0.\n",
+       "\n",
+       "rainbow :-\n",
+       "    rains,\n",
+       "    'The sun is shining'.\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:rainbow/0\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "carry_umbrella :- rains, 'I am not wearing a hat'.\n",
+    "rainbow :- rains, 'The sun is shining'."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 51,
+   "id": "4e6314e8",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- rainbow."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "161b0f75",
+   "metadata": {},
+   "source": [
+    "The corresponding logic formula to the rule for `rainbow` is \n",
+    "`rainbow ← rains ∧ 'The sun is shining'`"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d7254b1b",
+   "metadata": {},
+   "source": [
+    "### Predicates\n",
+    "Instead of propositions we can also use predicates with arguments within our clauses. The arguments to predicates denote objects for which the predicate is true. Arguments which start with an upper-case letter are logical variables. Below ```X``` is such a variable and it can stand for any object."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5f5810f7",
+   "metadata": {},
+   "source": [
+    "Prolog provides a few built-in predicates like `>` or `=` or `is`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c646de97",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1;31mfalse"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- 2>3."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 53,
+   "id": "600c0ea6",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mX = 5"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- is(X,3+2)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "0686241a",
+   "metadata": {},
+   "source": [
+    "Let us now define our own predicates.\n",
+    "In this case `mother/2` and `grandma/2`.\n",
+    "Note: we often use the notation `p/n` to denote the fact that the predicate `p` takes `n` arguments. `n` is called the arity of `p`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 54,
+   "id": "1d6eed4f",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:mother/2 were retracted (click to expand)</summary><pre>:- dynamic mother/2.\n",
+       "\n",
+       "mother(a, b).\n",
+       "mother(b, c).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:mother/2 were retracted:\n",
+       ":- dynamic mother/2.\n",
+       "\n",
+       "mother(a, b).\n",
+       "mother(b, c).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:mother/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:grandma/2 were retracted (click to expand)</summary><pre>:- dynamic grandma/2.\n",
+       "\n",
+       "grandma(A, B) :-\n",
+       "    mother(A, C),\n",
+       "    mother(C, B).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:grandma/2 were retracted:\n",
+       ":- dynamic grandma/2.\n",
+       "\n",
+       "grandma(A, B) :-\n",
+       "    mother(A, C),\n",
+       "    mother(C, B).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:grandma/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "mother(a,b).\n",
+    "mother(b,c).\n",
+    "grandma(a,c) :- mother(a,b),mother(b,c)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e645f31e",
+   "metadata": {},
+   "source": [
+    "You can now ask questions about logical consequences of your logic program. In simple queries you provide all arguments:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 55,
+   "id": "a2ab9e95",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?-grandma(a,c)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 56,
+   "id": "838bc91a",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- grandma(a,c) ; mother(c,d)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c8d0600e",
+   "metadata": {},
+   "source": [
+    "## Logical variables\n",
+    "Variables start with an upper-case letter or an underscore.\n",
+    "Variables are called `logical variables` in Prolog: once assigned, their value is immutable and cannot be changed (except upon backtracking)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 57,
+   "id": "93e47505",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mX = 1"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- X=1."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d82e2815",
+   "metadata": {},
+   "source": [
+    "Above we have set the logical variable `X` to 1. The scope of the name `X` is a Prolog clause (i.e., a fact or rule or a query). Thus, in the query below we talk about another `X`:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 58,
+   "id": "0c4d96e2",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mX = 2"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- X=2."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "3a3b14b8",
+   "metadata": {},
+   "source": [
+    "However, in the same scope we cannot change the value of `X`, once assigned:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "47e57f93",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1;31mfalse"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- X=1, X=2."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 60,
+   "id": "d9369af3",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mX = 1,\n",
+       "X2 = 2"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- X=1, X2 is X+1."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fdbee9bb",
+   "metadata": {},
+   "source": [
+    "Within a clause variables are implicitly unversally quantified.\n",
+    "Let us now define the grandma predicate in a more general fashion:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 61,
+   "id": "7fd70461",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:grandma/2 were retracted (click to expand)</summary><pre>:- dynamic grandma/2.\n",
+       "\n",
+       "grandma(a, c) :-\n",
+       "    mother(a, b),\n",
+       "    mother(b, c).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:grandma/2 were retracted:\n",
+       ":- dynamic grandma/2.\n",
+       "\n",
+       "grandma(a, c) :-\n",
+       "    mother(a, b),\n",
+       "    mother(b, c).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:grandma/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "grandma(X,Y) :- mother(X,Z), mother(Z,Y)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "51f5f6a4",
+   "metadata": {},
+   "source": [
+    "The above clause is equivalent to this logical formula:\n",
+    "\n",
+    "`∀ X,Y,Z . grandma(X,Y) ← mother(X,Z)∧ mother(Z,Y)`\n",
+    "\n",
+    "Let us query the predicate:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 62,
+   "id": "81724623",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mX = c"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- grandma(a,X)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "3dce4ccd",
+   "metadata": {},
+   "source": [
+    "When we have variables in a query, Prolog gives us solutions for variables such that the instantiated predicate calls are logical consequences of your program.\n",
+    "\n",
+    "We can find all solutions using the `print_table` command of our Jupyter kernel:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 63,
+   "id": "4d656338",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/markdown": [
+       "X | \n",
+       ":- | \n",
+       "c | "
+      ],
+      "text/plain": [
+       "X | \n",
+       ":- | \n",
+       "c | "
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "jupyter:print_table(grandma(a,X))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d90546b0",
+   "metadata": {},
+   "source": [
+    "Prolog also has a built-in predicate called ```findall``` which can be used to find all solutions in one go:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 64,
+   "id": "a7478245",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mResults = [c]"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?-findall(X,grandma(a,X),Results)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "74c96ce2",
+   "metadata": {},
+   "source": [
+    "### Prolog terms and substitutions\n",
+    "\n",
+    "Terms represent data values (aka objects). We have that\n",
+    "- constants like `a` and `b` are terms\n",
+    "- variables like `X` are terms\n",
+    "- terms can also be constructed using function symbols\n",
+    "\n",
+    "A predicate call takes terms as arguments.\n",
+    "E.g. for `grandma(a,X)` we have the term `a` as first argument and the term `X` as second argument."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fd8a78b7",
+   "metadata": {},
+   "source": [
+    "## Exercise\n",
+    "Let us try exercise 2.1.1 (iii) from the Art of Prolog (https://mitpress.mit.edu/9780262691635/the-art-of-prolog/), describing the layout of Figure 2.3 using `left_of/2` and `above/2`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 65,
+   "id": "9e3be61b",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:left_of/2 were retracted (click to expand)</summary><pre>:- dynamic left_of/2.\n",
+       "\n",
+       "left_of(bicycle, camera).\n",
+       "left_of(pencil, hourglass).\n",
+       "left_of(hourglass, butterfly).\n",
+       "left_of(butterfly, fish).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:left_of/2 were retracted:\n",
+       ":- dynamic left_of/2.\n",
+       "\n",
+       "left_of(bicycle, camera).\n",
+       "left_of(pencil, hourglass).\n",
+       "left_of(hourglass, butterfly).\n",
+       "left_of(butterfly, fish).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:left_of/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:above/2 were retracted (click to expand)</summary><pre>:- dynamic above/2.\n",
+       "\n",
+       "above(bicycle, pencil).\n",
+       "above(camera, butterfly).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:above/2 were retracted:\n",
+       ":- dynamic above/2.\n",
+       "\n",
+       "above(bicycle, pencil).\n",
+       "above(camera, butterfly).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:above/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "left_of(bicycle,camera).\n",
+    "left_of(pencil,hourglass).\n",
+    "left_of(hourglass,butterfly).\n",
+    "left_of(butterfly,fish).\n",
+    "\n",
+    "above(bicycle,pencil).\n",
+    "above(camera,butterfly)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "db2baf14",
+   "metadata": {},
+   "source": [
+    "We can use the Jupyter notebook to render the graph.\n",
+    "The `print_transition_graph` predicate requires a ternary predicate,\n",
+    "so that we can provide the edge labels:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 66,
+   "id": "6781d789",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:edge/3 were retracted (click to expand)</summary><pre>:- dynamic edge/3.\n",
+       "\n",
+       "edge(A, above, B) :-\n",
+       "    above(A, B).\n",
+       "edge(A, left_of, B) :-\n",
+       "    left_of(A, B).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:edge/3 were retracted:\n",
+       ":- dynamic edge/3.\n",
+       "\n",
+       "edge(A, above, B) :-\n",
+       "    above(A, B).\n",
+       "edge(A, left_of, B) :-\n",
+       "    left_of(A, B).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:edge/3\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "edge(A,above,B) :- above(A,B).\n",
+    "edge(A,left_of,B) :- left_of(A,B)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 67,
+   "id": "bb98ad05",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mA = bicycle,\n",
+       "B = above,\n",
+       "C = pencil"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- edge(A,B,C)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 68,
+   "id": "186fe078",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "image/svg+xml": [
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
+       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
+       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
+       "<!-- Generated by graphviz version 6.0.1 (20220911.1526)\n",
+       " -->\n",
+       "<!-- Pages: 1 -->\n",
+       "<svg width=\"168pt\" height=\"413pt\"\n",
+       " viewBox=\"0.00 0.00 167.59 413.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
+       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 409)\">\n",
+       "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-409 163.59,-409 163.59,4 -4,4\"/>\n",
+       "<!-- bicycle -->\n",
+       "<g id=\"node1\" class=\"node\">\n",
+       "<title>bicycle</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"86.2\" cy=\"-387\" rx=\"36.29\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"86.2\" y=\"-383.3\" font-family=\"Times,serif\" font-size=\"14.00\">bicycle</text>\n",
+       "</g>\n",
+       "<!-- pencil -->\n",
+       "<g id=\"node2\" class=\"node\">\n",
+       "<title>pencil</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"54.2\" cy=\"-300\" rx=\"32.49\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"54.2\" y=\"-296.3\" font-family=\"Times,serif\" font-size=\"14.00\">pencil</text>\n",
+       "</g>\n",
+       "<!-- bicycle&#45;&gt;pencil -->\n",
+       "<g id=\"edge1\" class=\"edge\">\n",
+       "<title>bicycle&#45;&gt;pencil</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M73.75,-370.02C69.83,-364.3 65.84,-357.62 63.2,-351 60.35,-343.87 58.4,-335.82 57.07,-328.28\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"60.49,-327.51 55.56,-318.14 53.57,-328.54 60.49,-327.51\"/>\n",
+       "<text text-anchor=\"middle\" x=\"79.7\" y=\"-339.8\" font-family=\"Times,serif\" font-size=\"14.00\">above</text>\n",
+       "</g>\n",
+       "<!-- camera -->\n",
+       "<g id=\"node3\" class=\"node\">\n",
+       "<title>camera</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"123.2\" cy=\"-246\" rx=\"36.29\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"123.2\" y=\"-242.3\" font-family=\"Times,serif\" font-size=\"14.00\">camera</text>\n",
+       "</g>\n",
+       "<!-- bicycle&#45;&gt;camera -->\n",
+       "<g id=\"edge3\" class=\"edge\">\n",
+       "<title>bicycle&#45;&gt;camera</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M91.16,-368.93C92.8,-363.24 94.6,-356.85 96.2,-351 103.33,-324.83 111.07,-294.83 116.43,-273.8\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"119.86,-274.52 118.93,-263.97 113.07,-272.8 119.86,-274.52\"/>\n",
+       "<text text-anchor=\"middle\" x=\"117.7\" y=\"-339.8\" font-family=\"Times,serif\" font-size=\"14.00\">left_of</text>\n",
+       "</g>\n",
+       "<!-- hourglass -->\n",
+       "<g id=\"node5\" class=\"node\">\n",
+       "<title>hourglass</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"44.2\" cy=\"-192\" rx=\"44.39\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"44.2\" y=\"-188.3\" font-family=\"Times,serif\" font-size=\"14.00\">hourglass</text>\n",
+       "</g>\n",
+       "<!-- pencil&#45;&gt;hourglass -->\n",
+       "<g id=\"edge4\" class=\"edge\">\n",
+       "<title>pencil&#45;&gt;hourglass</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M46.6,-282.25C44.4,-276.58 42.3,-270.12 41.2,-264 38.61,-249.63 39.06,-233.37 40.29,-220.04\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"43.77,-220.39 41.4,-210.07 36.81,-219.62 43.77,-220.39\"/>\n",
+       "<text text-anchor=\"middle\" x=\"59.7\" y=\"-242.3\" font-family=\"Times,serif\" font-size=\"14.00\">left_of</text>\n",
+       "</g>\n",
+       "<!-- butterfly -->\n",
+       "<g id=\"node4\" class=\"node\">\n",
+       "<title>butterfly</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"84.2\" cy=\"-105\" rx=\"40.89\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"84.2\" y=\"-101.3\" font-family=\"Times,serif\" font-size=\"14.00\">butterfly</text>\n",
+       "</g>\n",
+       "<!-- camera&#45;&gt;butterfly -->\n",
+       "<g id=\"edge2\" class=\"edge\">\n",
+       "<title>camera&#45;&gt;butterfly</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M122.78,-227.86C121.78,-206.77 118.41,-170.16 107.2,-141 105.9,-137.64 104.25,-134.27 102.43,-131.02\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"105.24,-128.92 96.98,-122.29 99.3,-132.63 105.24,-128.92\"/>\n",
+       "<text text-anchor=\"middle\" x=\"137.7\" y=\"-188.3\" font-family=\"Times,serif\" font-size=\"14.00\">above</text>\n",
+       "</g>\n",
+       "<!-- fish -->\n",
+       "<g id=\"node6\" class=\"node\">\n",
+       "<title>fish</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"84.2\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"84.2\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">fish</text>\n",
+       "</g>\n",
+       "<!-- butterfly&#45;&gt;fish -->\n",
+       "<g id=\"edge6\" class=\"edge\">\n",
+       "<title>butterfly&#45;&gt;fish</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M84.2,-86.8C84.2,-75.16 84.2,-59.55 84.2,-46.24\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"87.7,-46.18 84.2,-36.18 80.7,-46.18 87.7,-46.18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"102.7\" y=\"-57.8\" font-family=\"Times,serif\" font-size=\"14.00\">left_of</text>\n",
+       "</g>\n",
+       "<!-- hourglass&#45;&gt;butterfly -->\n",
+       "<g id=\"edge5\" class=\"edge\">\n",
+       "<title>hourglass&#45;&gt;butterfly</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M52.1,-174.21C57.74,-162.22 65.44,-145.85 71.89,-132.16\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"75.22,-133.3 76.31,-122.76 68.88,-130.32 75.22,-133.3\"/>\n",
+       "<text text-anchor=\"middle\" x=\"84.7\" y=\"-144.8\" font-family=\"Times,serif\" font-size=\"14.00\">left_of</text>\n",
+       "</g>\n",
+       "</g>\n",
+       "</svg>\n"
+      ],
+      "text/plain": [
+       "digraph {\n",
+       "    \"bicycle\" -> \"pencil\" [label=\"above\"]\n",
+       "    \"camera\" -> \"butterfly\" [label=\"above\"]\n",
+       "    \"bicycle\" -> \"camera\" [label=\"left_of\"]\n",
+       "    \"pencil\" -> \"hourglass\" [label=\"left_of\"]\n",
+       "    \"hourglass\" -> \"butterfly\" [label=\"left_of\"]\n",
+       "    \"butterfly\" -> \"fish\" [label=\"left_of\"]\n",
+       "}"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "jupyter:print_transition_graph(edge/3, 1, 3, 2)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "4ffad2ee",
+   "metadata": {},
+   "source": [
+    "We now define the predicates `right_of` and `below` in terms of the existing predicates:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 69,
+   "id": "de721f76",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:right_of/2 were retracted (click to expand)</summary><pre>:- dynamic right_of/2.\n",
+       "\n",
+       "right_of(A, B) :-\n",
+       "    left_of(B, A).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:right_of/2 were retracted:\n",
+       ":- dynamic right_of/2.\n",
+       "\n",
+       "right_of(A, B) :-\n",
+       "    left_of(B, A).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:right_of/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:below/2 were retracted (click to expand)</summary><pre>:- dynamic below/2.\n",
+       "\n",
+       "below(A, B) :-\n",
+       "    above(B, A).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:below/2 were retracted:\n",
+       ":- dynamic below/2.\n",
+       "\n",
+       "below(A, B) :-\n",
+       "    above(B, A).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:below/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "right_of(X,Y) :- left_of(Y,X).\n",
+    "below(X,Y) :- above(Y,X)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 70,
+   "id": "ea9e3961",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/markdown": [
+       "X | Y | \n",
+       ":- | :- | \n",
+       "camera | bicycle | \n",
+       "hourglass | pencil | \n",
+       "butterfly | hourglass | \n",
+       "fish | butterfly | "
+      ],
+      "text/plain": [
+       "X | Y | \n",
+       ":- | :- | \n",
+       "camera | bicycle | \n",
+       "hourglass | pencil | \n",
+       "butterfly | hourglass | \n",
+       "fish | butterfly | "
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "jupyter:print_table(right_of(X,Y))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 71,
+   "id": "9febc43e",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:next/2 were retracted (click to expand)</summary><pre>:- dynamic next/2.\n",
+       "\n",
+       "next(A, B) :-\n",
+       "    edge(A, _, B).\n",
+       "next(A, B) :-\n",
+       "    edge(B, _, A).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:next/2 were retracted:\n",
+       ":- dynamic next/2.\n",
+       "\n",
+       "next(A, B) :-\n",
+       "    edge(A, _, B).\n",
+       "next(A, B) :-\n",
+       "    edge(B, _, A).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:next/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "% next(A,B) :- above(A,B); below(A,B) ; left_of(A,B) ; right_of(A,B).\n",
+    "next(A,B) :- edge(A,_,B).\n",
+    "next(A,B) :- edge(B,_,A)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 72,
+   "id": "180088b8",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/markdown": [
+       "X | Y | \n",
+       ":- | :- | \n",
+       "bicycle | pencil | \n",
+       "camera | butterfly | \n",
+       "bicycle | camera | \n",
+       "pencil | hourglass | \n",
+       "hourglass | butterfly | \n",
+       "butterfly | fish | \n",
+       "pencil | bicycle | \n",
+       "butterfly | camera | \n",
+       "camera | bicycle | \n",
+       "hourglass | pencil | \n",
+       "butterfly | hourglass | \n",
+       "fish | butterfly | "
+      ],
+      "text/plain": [
+       "X | Y | \n",
+       ":- | :- | \n",
+       "bicycle | pencil | \n",
+       "camera | butterfly | \n",
+       "bicycle | camera | \n",
+       "pencil | hourglass | \n",
+       "hourglass | butterfly | \n",
+       "butterfly | fish | \n",
+       "pencil | bicycle | \n",
+       "butterfly | camera | \n",
+       "camera | bicycle | \n",
+       "hourglass | pencil | \n",
+       "butterfly | hourglass | \n",
+       "fish | butterfly | "
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "jupyter:print_table(next(X,Y))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "aacfbf9d",
+   "metadata": {},
+   "source": [
+    "## Recursion\n",
+    "\n",
+    "Recursion is also allowed in Prolog rules.\n",
+    "We now define the simple graph of Figure 2.4 of the Art of Prolog as Prolog facts.\n",
+    "\n",
+    "Note that Prolog allows the same predicate name to be used with multiple arities.\n",
+    "Above we have defined `edge/3`, below we define `edge/2`. For Prolog these two\n",
+    "predicates are different and there is no confusion within the Prolog system.\n",
+    "However, for programmers it can be a bit tricky to read code which uses\n",
+    "the same predicate name with multiple arities."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 73,
+   "id": "12f78859",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:edge/2 were retracted (click to expand)</summary><pre>:- dynamic edge/2.\n",
+       "\n",
+       "edge(a, b).\n",
+       "edge(a, c).\n",
+       "edge(b, d).\n",
+       "edge(c, d).\n",
+       "edge(d, e).\n",
+       "edge(f, g).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:edge/2 were retracted:\n",
+       ":- dynamic edge/2.\n",
+       "\n",
+       "edge(a, b).\n",
+       "edge(a, c).\n",
+       "edge(b, d).\n",
+       "edge(c, d).\n",
+       "edge(d, e).\n",
+       "edge(f, g).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:edge/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "edge(a,b). edge(a,c).\n",
+    "edge(b,d). edge(c,d).\n",
+    "edge(d,e).\n",
+    "edge(f,g)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "16ffb236",
+   "metadata": {},
+   "source": [
+    "With the underscore we indicate that we are not interested in an argument; it is an anonymous logical variable. Here we use this to find the last element of a list:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 74,
+   "id": "99bfae95",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "image/svg+xml": [
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
+       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
+       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
+       "<!-- Generated by graphviz version 6.0.1 (20220911.1526)\n",
+       " -->\n",
+       "<!-- Pages: 1 -->\n",
+       "<svg width=\"206pt\" height=\"260pt\"\n",
+       " viewBox=\"0.00 0.00 206.00 260.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
+       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 256)\">\n",
+       "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-256 202,-256 202,4 -4,4\"/>\n",
+       "<!-- a -->\n",
+       "<g id=\"node1\" class=\"node\">\n",
+       "<title>a</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"63\" cy=\"-234\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"63\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">a</text>\n",
+       "</g>\n",
+       "<!-- b -->\n",
+       "<g id=\"node2\" class=\"node\">\n",
+       "<title>b</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"27\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">b</text>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;b -->\n",
+       "<g id=\"edge1\" class=\"edge\">\n",
+       "<title>a&#45;&gt;b</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M54.65,-216.76C50.29,-208.28 44.85,-197.71 39.96,-188.2\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"42.99,-186.44 35.3,-179.15 36.77,-189.64 42.99,-186.44\"/>\n",
+       "</g>\n",
+       "<!-- c -->\n",
+       "<g id=\"node3\" class=\"node\">\n",
+       "<title>c</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"99\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">c</text>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;c -->\n",
+       "<g id=\"edge2\" class=\"edge\">\n",
+       "<title>a&#45;&gt;c</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M71.35,-216.76C75.71,-208.28 81.15,-197.71 86.04,-188.2\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"89.23,-189.64 90.7,-179.15 83.01,-186.44 89.23,-189.64\"/>\n",
+       "</g>\n",
+       "<!-- d -->\n",
+       "<g id=\"node4\" class=\"node\">\n",
+       "<title>d</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"63\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"63\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">d</text>\n",
+       "</g>\n",
+       "<!-- b&#45;&gt;d -->\n",
+       "<g id=\"edge3\" class=\"edge\">\n",
+       "<title>b&#45;&gt;d</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M35.35,-144.76C39.71,-136.28 45.15,-125.71 50.04,-116.2\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"53.23,-117.64 54.7,-107.15 47.01,-114.44 53.23,-117.64\"/>\n",
+       "</g>\n",
+       "<!-- c&#45;&gt;d -->\n",
+       "<g id=\"edge4\" class=\"edge\">\n",
+       "<title>c&#45;&gt;d</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M90.65,-144.76C86.29,-136.28 80.85,-125.71 75.96,-116.2\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"78.99,-114.44 71.3,-107.15 72.77,-117.64 78.99,-114.44\"/>\n",
+       "</g>\n",
+       "<!-- e -->\n",
+       "<g id=\"node5\" class=\"node\">\n",
+       "<title>e</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"63\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"63\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">e</text>\n",
+       "</g>\n",
+       "<!-- d&#45;&gt;e -->\n",
+       "<g id=\"edge5\" class=\"edge\">\n",
+       "<title>d&#45;&gt;e</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M63,-71.7C63,-63.98 63,-54.71 63,-46.11\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"66.5,-46.1 63,-36.1 59.5,-46.1 66.5,-46.1\"/>\n",
+       "</g>\n",
+       "<!-- f -->\n",
+       "<g id=\"node6\" class=\"node\">\n",
+       "<title>f</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-234\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"171\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">f</text>\n",
+       "</g>\n",
+       "<!-- g -->\n",
+       "<g id=\"node7\" class=\"node\">\n",
+       "<title>g</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"171\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">g</text>\n",
+       "</g>\n",
+       "<!-- f&#45;&gt;g -->\n",
+       "<g id=\"edge6\" class=\"edge\">\n",
+       "<title>f&#45;&gt;g</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M171,-215.7C171,-207.98 171,-198.71 171,-190.11\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"174.5,-190.1 171,-180.1 167.5,-190.1 174.5,-190.1\"/>\n",
+       "</g>\n",
+       "</g>\n",
+       "</svg>\n"
+      ],
+      "text/plain": [
+       "digraph {\n",
+       "    \"a\" -> \"b\"\n",
+       "    \"a\" -> \"c\"\n",
+       "    \"b\" -> \"d\"\n",
+       "    \"c\" -> \"d\"\n",
+       "    \"d\" -> \"e\"\n",
+       "    \"f\" -> \"g\"\n",
+       "}"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "jupyter:print_transition_graph(edge/2, 1, 2,0)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 75,
+   "id": "7a790ea4",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:conn/2 were retracted (click to expand)</summary><pre>:- dynamic conn/2.\n",
+       "\n",
+       "conn(A, A).\n",
+       "conn(A, B) :-\n",
+       "    edge(A, C),\n",
+       "    conn(C, B).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:conn/2 were retracted:\n",
+       ":- dynamic conn/2.\n",
+       "\n",
+       "conn(A, A).\n",
+       "conn(A, B) :-\n",
+       "    edge(A, C),\n",
+       "    conn(C, B).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:conn/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "conn(A,A) :- true.\n",
+    "%conn(X,Y) :- edge(X,Y).\n",
+    "conn(X,Y) :- edge(X,Z), conn(Z,Y)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 76,
+   "id": "440d2412",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/markdown": [
+       "X | \n",
+       ":- | \n",
+       "a | \n",
+       "b | \n",
+       "d | \n",
+       "e | \n",
+       "c | \n",
+       "d | \n",
+       "e | "
+      ],
+      "text/plain": [
+       "X | \n",
+       ":- | \n",
+       "a | \n",
+       "b | \n",
+       "d | \n",
+       "e | \n",
+       "c | \n",
+       "d | \n",
+       "e | "
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- jupyter:print_table(conn(a,X))."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 77,
+   "id": "f50f25de",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mLs = [a,b,d,e,c,d,e],\n",
+       "Len = 7"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- findall(X, conn(a,X),Ls), length(Ls,Len)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "466ece27",
+   "metadata": {},
+   "source": [
+    "Let us now try and define the transitive and reflexive closure of edge."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 78,
+   "id": "5627c07e",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:connected/2 were retracted (click to expand)</summary><pre>:- dynamic connected/2.\n",
+       "\n",
+       "connected(A, A).\n",
+       "connected(A, B) :-\n",
+       "    edge(A, C),\n",
+       "    connected(C, B).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:connected/2 were retracted:\n",
+       ":- dynamic connected/2.\n",
+       "\n",
+       "connected(A, A).\n",
+       "connected(A, B) :-\n",
+       "    edge(A, C),\n",
+       "    connected(C, B).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:connected/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "connected(N,N).\n",
+    "connected(N1,N2) :- edge(N1,Link), connected(Link,N2)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 79,
+   "id": "428e3101",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mX = a"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- connected(a,X)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 80,
+   "id": "ae00f8b8",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "image/svg+xml": [
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
+       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
+       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
+       "<!-- Generated by graphviz version 6.0.1 (20220911.1526)\n",
+       " -->\n",
+       "<!-- Pages: 1 -->\n",
+       "<svg width=\"340pt\" height=\"260pt\"\n",
+       " viewBox=\"0.00 0.00 340.05 260.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
+       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 256)\">\n",
+       "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-256 336.05,-256 336.05,4 -4,4\"/>\n",
+       "<!-- _20642 -->\n",
+       "<g id=\"node1\" class=\"node\">\n",
+       "<title>_20642</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"37.05\" cy=\"-234\" rx=\"37.09\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"37.05\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">_20642</text>\n",
+       "</g>\n",
+       "<!-- _20642&#45;&gt;_20642 -->\n",
+       "<g id=\"edge1\" class=\"edge\">\n",
+       "<title>_20642&#45;&gt;_20642</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M63.38,-246.81C78.29,-249.31 92.09,-245.04 92.09,-234 92.09,-225.55 84,-221.06 73.52,-220.55\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"73.14,-217.07 63.38,-221.19 73.58,-224.05 73.14,-217.07\"/>\n",
+       "</g>\n",
+       "<!-- a -->\n",
+       "<g id=\"node2\" class=\"node\">\n",
+       "<title>a</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"137.05\" cy=\"-234\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"137.05\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">a</text>\n",
+       "</g>\n",
+       "<!-- b -->\n",
+       "<g id=\"node3\" class=\"node\">\n",
+       "<title>b</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"105.05\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"105.05\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">b</text>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;b -->\n",
+       "<g id=\"edge2\" class=\"edge\">\n",
+       "<title>a&#45;&gt;b</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M129.46,-216.41C125.68,-208.13 121.01,-197.92 116.78,-188.66\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"119.92,-187.11 112.58,-179.47 113.55,-190.02 119.92,-187.11\"/>\n",
+       "</g>\n",
+       "<!-- d -->\n",
+       "<g id=\"node4\" class=\"node\">\n",
+       "<title>d</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"169.05\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"169.05\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">d</text>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;d -->\n",
+       "<g id=\"edge3\" class=\"edge\">\n",
+       "<title>a&#45;&gt;d</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M136.32,-215.87C139.26,-191.3 149.24,-145.85 157.8,-117.08\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"161.21,-117.9 160.87,-107.31 154.54,-115.8 161.21,-117.9\"/>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;d -->\n",
+       "<g id=\"edge6\" class=\"edge\">\n",
+       "<title>a&#45;&gt;d</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M145.21,-216.71C153.26,-192.7 163.77,-147.53 168.34,-118.37\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"171.81,-118.82 169.74,-108.43 164.88,-117.84 171.81,-118.82\"/>\n",
+       "</g>\n",
+       "<!-- e -->\n",
+       "<g id=\"node5\" class=\"node\">\n",
+       "<title>e</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"105.05\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"105.05\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">e</text>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;e -->\n",
+       "<g id=\"edge4\" class=\"edge\">\n",
+       "<title>a&#45;&gt;e</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M113.16,-225.31C94.49,-216.84 70.56,-201.52 60.05,-180 37.64,-134.13 63.89,-74.08 84.94,-41.84\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"87.88,-43.74 90.69,-33.52 82.12,-39.75 87.88,-43.74\"/>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;e -->\n",
+       "<g id=\"edge7\" class=\"edge\">\n",
+       "<title>a&#45;&gt;e</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M118.83,-220.44C104.8,-211.49 86.78,-197.89 78.05,-180 56.4,-135.69 80.16,-78.15 95.3,-45.22\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"98.62,-46.38 99.66,-35.84 92.27,-43.43 98.62,-46.38\"/>\n",
+       "</g>\n",
+       "<!-- c -->\n",
+       "<g id=\"node6\" class=\"node\">\n",
+       "<title>c</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"233.05\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"233.05\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">c</text>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;c -->\n",
+       "<g id=\"edge5\" class=\"edge\">\n",
+       "<title>a&#45;&gt;c</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M154.65,-220.16C169.4,-209.41 190.66,-193.91 207.32,-181.76\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"209.53,-184.48 215.55,-175.76 205.41,-178.82 209.53,-184.48\"/>\n",
+       "</g>\n",
+       "<!-- b&#45;&gt;d -->\n",
+       "<g id=\"edge8\" class=\"edge\">\n",
+       "<title>b&#45;&gt;d</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M118.62,-146.15C127.36,-136.6 138.88,-123.99 148.7,-113.25\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"151.33,-115.57 155.49,-105.82 146.16,-110.84 151.33,-115.57\"/>\n",
+       "</g>\n",
+       "<!-- b&#45;&gt;e -->\n",
+       "<g id=\"edge9\" class=\"edge\">\n",
+       "<title>b&#45;&gt;e</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M105.05,-143.87C105.05,-119.67 105.05,-75.21 105.05,-46.39\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"108.55,-46.19 105.05,-36.19 101.55,-46.19 108.55,-46.19\"/>\n",
+       "</g>\n",
+       "<!-- d&#45;&gt;e -->\n",
+       "<g id=\"edge12\" class=\"edge\">\n",
+       "<title>d&#45;&gt;e</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M155.47,-74.15C146.73,-64.6 135.21,-51.99 125.39,-41.25\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"127.93,-38.84 118.6,-33.82 122.76,-43.57 127.93,-38.84\"/>\n",
+       "</g>\n",
+       "<!-- c&#45;&gt;d -->\n",
+       "<g id=\"edge10\" class=\"edge\">\n",
+       "<title>c&#45;&gt;d</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M219.47,-146.15C210.73,-136.6 199.21,-123.99 189.39,-113.25\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"191.93,-110.84 182.6,-105.82 186.76,-115.57 191.93,-110.84\"/>\n",
+       "</g>\n",
+       "<!-- c&#45;&gt;e -->\n",
+       "<g id=\"edge11\" class=\"edge\">\n",
+       "<title>c&#45;&gt;e</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M231.52,-143.75C228.99,-124.33 222.35,-92.79 205.05,-72 187.93,-51.44 160.74,-37.76 139.03,-29.45\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"140.09,-26.11 129.49,-26.01 137.71,-32.7 140.09,-26.11\"/>\n",
+       "</g>\n",
+       "<!-- f -->\n",
+       "<g id=\"node7\" class=\"node\">\n",
+       "<title>f</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"305.05\" cy=\"-234\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"305.05\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">f</text>\n",
+       "</g>\n",
+       "<!-- g -->\n",
+       "<g id=\"node8\" class=\"node\">\n",
+       "<title>g</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"305.05\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"305.05\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">g</text>\n",
+       "</g>\n",
+       "<!-- f&#45;&gt;g -->\n",
+       "<g id=\"edge13\" class=\"edge\">\n",
+       "<title>f&#45;&gt;g</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M305.05,-215.7C305.05,-207.98 305.05,-198.71 305.05,-190.11\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"308.55,-190.1 305.05,-180.1 301.55,-190.1 308.55,-190.1\"/>\n",
+       "</g>\n",
+       "</g>\n",
+       "</svg>\n"
+      ],
+      "text/plain": [
+       "digraph {\n",
+       "    \"_20642\" -> \"_20642\"\n",
+       "    \"a\" -> \"b\"\n",
+       "    \"a\" -> \"d\"\n",
+       "    \"a\" -> \"e\"\n",
+       "    \"a\" -> \"c\"\n",
+       "    \"a\" -> \"d\"\n",
+       "    \"a\" -> \"e\"\n",
+       "    \"b\" -> \"d\"\n",
+       "    \"b\" -> \"e\"\n",
+       "    \"c\" -> \"d\"\n",
+       "    \"c\" -> \"e\"\n",
+       "    \"d\" -> \"e\"\n",
+       "    \"f\" -> \"g\"\n",
+       "}"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "jupyter:print_transition_graph(connected/2, 1, 2,0)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fa7eb5e5",
+   "metadata": {},
+   "source": [
+    "How should we adapt the definition to only provide the transitive (non-reflexive) closure?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 81,
+   "id": "4ac0a146",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:conn1/2 were retracted (click to expand)</summary><pre>:- dynamic conn1/2.\n",
+       "\n",
+       "conn1(A, B) :-\n",
+       "    edge(A, B).\n",
+       "conn1(A, B) :-\n",
+       "    edge(A, C),\n",
+       "    conn1(C, B).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:conn1/2 were retracted:\n",
+       ":- dynamic conn1/2.\n",
+       "\n",
+       "conn1(A, B) :-\n",
+       "    edge(A, B).\n",
+       "conn1(A, B) :-\n",
+       "    edge(A, C),\n",
+       "    conn1(C, B).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:conn1/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "conn1(X,Y) :- edge(X,Y).\n",
+    "conn1(N1,N2) :- edge(N1,Link), conn1(Link,N2)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 82,
+   "id": "713979ea",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mX = b"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- conn1(a,X)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 83,
+   "id": "edfb9af1",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "image/svg+xml": [
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
+       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
+       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
+       "<!-- Generated by graphviz version 6.0.1 (20220911.1526)\n",
+       " -->\n",
+       "<!-- Pages: 1 -->\n",
+       "<svg width=\"318pt\" height=\"260pt\"\n",
+       " viewBox=\"0.00 0.00 318.00 260.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
+       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 256)\">\n",
+       "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-256 314,-256 314,4 -4,4\"/>\n",
+       "<!-- a -->\n",
+       "<g id=\"node1\" class=\"node\">\n",
+       "<title>a</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"123\" cy=\"-234\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"123\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">a</text>\n",
+       "</g>\n",
+       "<!-- b -->\n",
+       "<g id=\"node2\" class=\"node\">\n",
+       "<title>b</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"27\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">b</text>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;b -->\n",
+       "<g id=\"edge1\" class=\"edge\">\n",
+       "<title>a&#45;&gt;b</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M105.39,-220.16C90.64,-209.41 69.39,-193.91 52.73,-181.76\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"54.64,-178.82 44.5,-175.76 50.51,-184.48 54.64,-178.82\"/>\n",
+       "</g>\n",
+       "<!-- c -->\n",
+       "<g id=\"node3\" class=\"node\">\n",
+       "<title>c</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"155\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"155\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">c</text>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;c -->\n",
+       "<g id=\"edge2\" class=\"edge\">\n",
+       "<title>a&#45;&gt;c</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M130.58,-216.41C134.37,-208.13 139.03,-197.92 143.27,-188.66\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"146.5,-190.02 147.47,-179.47 140.13,-187.11 146.5,-190.02\"/>\n",
+       "</g>\n",
+       "<!-- d -->\n",
+       "<g id=\"node4\" class=\"node\">\n",
+       "<title>d</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"91\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"91\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">d</text>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;d -->\n",
+       "<g id=\"edge7\" class=\"edge\">\n",
+       "<title>a&#45;&gt;d</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M114.84,-216.71C106.78,-192.7 96.28,-147.53 91.71,-118.37\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"95.17,-117.84 90.31,-108.43 88.24,-118.82 95.17,-117.84\"/>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;d -->\n",
+       "<g id=\"edge9\" class=\"edge\">\n",
+       "<title>a&#45;&gt;d</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M123.72,-215.87C120.78,-191.3 110.8,-145.85 102.25,-117.08\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"105.51,-115.8 99.17,-107.31 98.83,-117.9 105.51,-115.8\"/>\n",
+       "</g>\n",
+       "<!-- e -->\n",
+       "<g id=\"node5\" class=\"node\">\n",
+       "<title>e</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"155\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"155\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">e</text>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;e -->\n",
+       "<g id=\"edge8\" class=\"edge\">\n",
+       "<title>a&#45;&gt;e</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M141.22,-220.44C155.25,-211.49 173.26,-197.89 182,-180 203.65,-135.69 179.89,-78.15 164.75,-45.22\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"167.77,-43.43 160.39,-35.84 161.43,-46.38 167.77,-43.43\"/>\n",
+       "</g>\n",
+       "<!-- a&#45;&gt;e -->\n",
+       "<g id=\"edge10\" class=\"edge\">\n",
+       "<title>a&#45;&gt;e</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M146.88,-225.31C165.55,-216.84 189.49,-201.52 200,-180 222.41,-134.13 196.16,-74.08 175.11,-41.84\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"177.92,-39.75 169.36,-33.52 172.16,-43.74 177.92,-39.75\"/>\n",
+       "</g>\n",
+       "<!-- b&#45;&gt;d -->\n",
+       "<g id=\"edge3\" class=\"edge\">\n",
+       "<title>b&#45;&gt;d</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M40.57,-146.15C49.31,-136.6 60.83,-123.99 70.66,-113.25\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"73.28,-115.57 77.45,-105.82 68.12,-110.84 73.28,-115.57\"/>\n",
+       "</g>\n",
+       "<!-- b&#45;&gt;e -->\n",
+       "<g id=\"edge11\" class=\"edge\">\n",
+       "<title>b&#45;&gt;e</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M28.53,-143.75C31.05,-124.33 37.7,-92.79 55,-72 72.11,-51.44 99.31,-37.76 121.02,-29.45\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"122.34,-32.7 130.56,-26.01 119.96,-26.11 122.34,-32.7\"/>\n",
+       "</g>\n",
+       "<!-- c&#45;&gt;d -->\n",
+       "<g id=\"edge4\" class=\"edge\">\n",
+       "<title>c&#45;&gt;d</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M141.43,-146.15C132.69,-136.6 121.17,-123.99 111.34,-113.25\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"113.88,-110.84 104.55,-105.82 108.72,-115.57 113.88,-110.84\"/>\n",
+       "</g>\n",
+       "<!-- c&#45;&gt;e -->\n",
+       "<g id=\"edge12\" class=\"edge\">\n",
+       "<title>c&#45;&gt;e</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M155,-143.87C155,-119.67 155,-75.21 155,-46.39\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"158.5,-46.19 155,-36.19 151.5,-46.19 158.5,-46.19\"/>\n",
+       "</g>\n",
+       "<!-- d&#45;&gt;e -->\n",
+       "<g id=\"edge5\" class=\"edge\">\n",
+       "<title>d&#45;&gt;e</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M104.57,-74.15C113.31,-64.6 124.83,-51.99 134.66,-41.25\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"137.28,-43.57 141.45,-33.82 132.12,-38.84 137.28,-43.57\"/>\n",
+       "</g>\n",
+       "<!-- f -->\n",
+       "<g id=\"node6\" class=\"node\">\n",
+       "<title>f</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"283\" cy=\"-234\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"283\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">f</text>\n",
+       "</g>\n",
+       "<!-- g -->\n",
+       "<g id=\"node7\" class=\"node\">\n",
+       "<title>g</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"283\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"283\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">g</text>\n",
+       "</g>\n",
+       "<!-- f&#45;&gt;g -->\n",
+       "<g id=\"edge6\" class=\"edge\">\n",
+       "<title>f&#45;&gt;g</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M283,-215.7C283,-207.98 283,-198.71 283,-190.11\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"286.5,-190.1 283,-180.1 279.5,-190.1 286.5,-190.1\"/>\n",
+       "</g>\n",
+       "</g>\n",
+       "</svg>\n"
+      ],
+      "text/plain": [
+       "digraph {\n",
+       "    \"a\" -> \"b\"\n",
+       "    \"a\" -> \"c\"\n",
+       "    \"b\" -> \"d\"\n",
+       "    \"c\" -> \"d\"\n",
+       "    \"d\" -> \"e\"\n",
+       "    \"f\" -> \"g\"\n",
+       "    \"a\" -> \"d\"\n",
+       "    \"a\" -> \"e\"\n",
+       "    \"a\" -> \"d\"\n",
+       "    \"a\" -> \"e\"\n",
+       "    \"b\" -> \"e\"\n",
+       "    \"c\" -> \"e\"\n",
+       "}"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "jupyter:print_transition_graph(conn1/2, 1, 2,0)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "7b4487b6",
+   "metadata": {},
+   "source": [
+    "## Arithmetic\n",
+    "Prolog provides integers and floating point numbers as primitive data structures.\n",
+    "With the `is` predicate we can for example compute with those numbers:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 84,
+   "id": "04ea12a1",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mX = 1606938044258990275541962092341162602522202993782792835301376"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- X is 2^200."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 85,
+   "id": "6056f98a",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mX = 2.0"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- X is 1.0+1."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "53b594a2",
+   "metadata": {},
+   "source": [
+    "# Compound data values\n",
+    "\n",
+    "So far we have seen these primitive Prolog data values:\n",
+    "- constants (called atoms in Prolog) like `a` and `b`\n",
+    "- integers\n",
+    "- floats\n",
+    "\n",
+    "More complex data values can be wrapped in so-called functors (also called function symbols).\n",
+    "Like predicates they have an arity and take terms as arguments.\n",
+    "Unlike predicates, they denote a value and not a logical truth value.\n",
+    "\n",
+    "This can be confusing to beginners: whether something is a predicate or functor depends on the position in the Prolog file:\n",
+    "- top-level symbols in Prolog clauses are predicates\n",
+    "- arguments to predicates and functors only contain functors\n",
+    "\n",
+    "Functors have many uses in Prolog. The can be used for simple records up to recursive data structures like lists or trees.\n",
+    "\n",
+    "Below we first use the functor `employe/2` as a simple record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 86,
+   "id": "d4664fd8",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:construct/3 were retracted (click to expand)</summary><pre>:- dynamic construct/3.\n",
+       "\n",
+       "construct(A, B, employe(A, B)).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:construct/3 were retracted:\n",
+       ":- dynamic construct/3.\n",
+       "\n",
+       "construct(A, B, employe(A, B)).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:construct/3\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:get_name/2 were retracted (click to expand)</summary><pre>:- dynamic get_name/2.\n",
+       "\n",
+       "get_name(employe(A, _), A).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:get_name/2 were retracted:\n",
+       ":- dynamic get_name/2.\n",
+       "\n",
+       "get_name(employe(A, _), A).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:get_name/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:get_dept/2 were retracted (click to expand)</summary><pre>:- dynamic get_dept/2.\n",
+       "\n",
+       "get_dept(employe(_, A), A).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:get_dept/2 were retracted:\n",
+       ":- dynamic get_dept/2.\n",
+       "\n",
+       "get_dept(employe(_, A), A).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:get_dept/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "\n",
+    "construct(Name,Department,employe(Name,Department)).\n",
+    "\n",
+    "get_name(employe(Name,_),Name).\n",
+    "get_dept(employe(_,Dept),Dept)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 87,
+   "id": "08715fa2",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mE1 = employe(a,cs),\n",
+       "E2 = employe(b,cs),\n",
+       "N1 = a,\n",
+       "D2 = cs"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- construct(a,cs,E1), construct(b,cs,E2), get_name(E1,N1), get_dept(E2,D2)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e2ed5de7",
+   "metadata": {},
+   "source": [
+    "The arguments to a functor can in term also make use of a functor.\n",
+    "\n",
+    "One could thus for example represent a list in Prolog by using\n",
+    "a functor `cons/2` to denote a non-empty list and `nil/0` to denote\n",
+    "an empty list.\n",
+    "Note that a functor of arity 0 is simply a constant (aka atom in Prolog).\n",
+    "So a list of length two with a and b as elements is represented as follows:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 88,
+   "id": "313194bb",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mMylist = cons(a,cons(b,nil))"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- Mylist = cons(a,cons(b,nil))."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "f2b1a0cd",
+   "metadata": {},
+   "source": [
+    "Let us now try and define some useful predicates for our data type:\n",
+    "- is_empty/1 to check if something is the empty list\n",
+    "- is_list/1 to check if something is a list\n",
+    "- head/1 to get the first element of a list\n",
+    "- element_of/2 to check if something is an element of a list\n",
+    "- last/1 to get the last elemetn of a list"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 89,
+   "id": "e0eed7cc",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "            <style>\n",
+       "            details  {\n",
+       "              font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n",
+       "            }\n",
+       "\n",
+       "            details > summary {\n",
+       "              cursor: pointer;\n",
+       "            }\n",
+       "            </style>\n",
+       "            <details><summary>Previously defined clauses of user:is_empty/1 were retracted (click to expand)</summary><pre>:- dynamic is_empty/1.\n",
+       "\n",
+       "is_empty(nil).\n",
+       "</pre></details>"
+      ],
+      "text/plain": [
+       "Previously defined clauses of user:is_empty/1 were retracted:\n",
+       ":- dynamic is_empty/1.\n",
+       "\n",
+       "is_empty(nil).\n"
+      ]
+     },
+     "metadata": {
+      "application/json": {}
+     },
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:is_empty/1\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "is_empty(nil) :- true."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "6efab831",
+   "metadata": {},
+   "source": [
+    "This should succeed:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 90,
+   "id": "82f68320",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- is_empty(nil)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "6c2de157",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1;31mfalse"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- is_empty(cons(a,nil))."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d0e8eb01",
+   "metadata": {},
+   "source": [
+    "Let us now define is_list0 (is_list is predefined):"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 92,
+   "id": "c2615402",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:is_list0/1\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:is_non_empty_list/1\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "is_list0(nil).\n",
+    "is_list0(cons(_,B)) :- is_list0(B).\n",
+    "\n",
+    "is_non_empty_list(cons(_,B)) :- is_list0(B)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 93,
+   "id": "d2b8accc",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?-is_list0(cons(employe(a,cs),cons(b,nil)))."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 94,
+   "id": "9cf37f7f",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:head/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "head(First,cons(First,_)) :- true."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 95,
+   "id": "05f68119",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mX = employe(a,b)"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- head(X,cons(employe(a,b),cons(b,nil)))."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 96,
+   "id": "bef84acb",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:element_of/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "element_of(First,cons(First,_)).\n",
+    "element_of(H,cons(_,T)) :- element_of(H,T)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 97,
+   "id": "b1707b0f",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mY = cons(c,_18628)"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- element_of(c,cons(a,cons(b,Y)))."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 98,
+   "id": "0cdcb148",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "% Retrying goal: element_of(c,cons(a,cons(b,Y)))\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mY = cons(_18626,cons(c,_18634))"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "jupyter:retry."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 99,
+   "id": "4365798d",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mFirst = a"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- element_of(First,cons(a,nil))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 100,
+   "id": "097687f9",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/markdown": [
+       "X | \n",
+       ":- | \n",
+       "a | \n",
+       "b | "
+      ],
+      "text/plain": [
+       "X | \n",
+       ":- | \n",
+       "a | \n",
+       "b | "
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "jupyter:print_table(element_of(X,cons(a,cons(b,nil))))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 101,
+   "id": "e3c67e2b",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:last0/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "last0(X,cons(X,nil)).\n",
+    "last0(X,cons(_,Y)) :- last0(X,Y)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 102,
+   "id": "1c91221d",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mX = b"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- last0(X,cons(a,cons(b,nil)))."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5f251e4d",
+   "metadata": {},
+   "source": [
+    "## Trees\n",
+    "\n",
+    "As a quick example let us represent binary trees using compound Prolog terms.\n",
+    "For this we use a ternary functor `tree/3`.\n",
+    "It has three arguments:\n",
+    "- the left sub-tree\n",
+    "- the information at the root of the tree\n",
+    "- the right sub-tree\n",
+    "We also need the empty tree, which we represent by `nil`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 103,
+   "id": "0dcf1d4c",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mMytree = tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- Mytree = tree(  tree(nil,a,nil), b, tree(nil,c,tree(nil,d,nil)))."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 104,
+   "id": "52fb0c11",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:revtree/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "revtree(nil,nil).\n",
+    "revtree(tree(L,Info,R),tree(RR,Info,RL)) :- revtree(L,RL), revtree(R,RR)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 105,
+   "id": "c3a7cd35",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mMytree = tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil))),\n",
+       "Result = tree(tree(tree(nil,d,nil),c,nil),b,tree(nil,a,nil))"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- Mytree = tree(  tree(nil,a,nil), b, tree(nil,c,tree(nil,d,nil))),\n",
+    "   revtree(Mytree,Result)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d883817f",
+   "metadata": {},
+   "source": [
+    "## Optional Appendix: Visualising data values as trees\n",
+    "\n",
+    "Below we try to use the Jupyter graph visualisation to represent data values\n",
+    "in a tree-like fashion."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 106,
+   "id": "ffe1cbc6",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [],
+   "source": [
+    ":- use_module(library(lists))."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "05730fc3",
+   "metadata": {},
+   "source": [
+    "We define a subtree relation, using the =.. built-in predicate, which deconstructs a term\n",
+    "by generating a list consisting of the function symbol and all its arguments:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 107,
+   "id": "39fc2aab",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mList = [tree,nil,a,nil]"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- tree(nil,a,nil) =.. List."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "4088fdfa",
+   "metadata": {},
+   "source": [
+    "We can now define a subtree relation:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 116,
+   "id": "536475da",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1;31m% The Prolog server was restarted"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:subtree/3\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "subtree(Term,Nr,SubTerm) :- Term =.. [_|List], nth1(Nr,List,SubTerm)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 117,
+   "id": "eb820f56",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mMytree = tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil))),\n",
+       "Nr = 1,\n",
+       "SubTerm = tree(nil,a,nil)"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- Mytree = tree(  tree(nil,a,nil), b, tree(nil,c,tree(nil,d,nil))),\n",
+    "   subtree(Mytree,Nr,SubTerm)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "69ae338f",
+   "metadata": {},
+   "source": [
+    "For the Jupyter graph visualisation we also need to restrict this relation and define a set of terms of interest.\n",
+    "Indeed, otherwise there are infinitely many terms.\n",
+    "\n",
+    "For this we define the transitive and reflexive closure of the subtree relation and only consider subtrees of a given starting term (here `tree(  tree(nil,a,nil), b, tree(nil,c,tree(nil,d,nil)))`)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 118,
+   "id": "4b4732c1",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:rec_subtree/2\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:of_interest/1\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "% Asserting clauses for user:subt/3\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "rec_subtree(Term,Sub) :- Term = Sub.\n",
+    "rec_subtree(Term,Sub) :- subtree(Term,_,X), rec_subtree(X,Sub).\n",
+    "\n",
+    "of_interest(Term) :- rec_subtree(tree(  tree(nil,a,nil), b, tree(nil,c,tree(nil,d,nil))),Term).\n",
+    "\n",
+    "subt(Term,Nr,SubTerm) :-\n",
+    "    of_interest(Term), % only consider subterms of the above term as nodes\n",
+    "    subtree(Term,Nr,SubTerm)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 119,
+   "id": "2992249a",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mMytree = tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil))),\n",
+       "Nr = 1,\n",
+       "SubTerm = tree(nil,a,nil)"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "?- Mytree = tree(  tree(nil,a,nil), b, tree(nil,c,tree(nil,d,nil))),\n",
+    "   subtree(Mytree,Nr,SubTerm)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 120,
+   "id": "2b76644b",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "image/svg+xml": [
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
+       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
+       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
+       "<!-- Generated by graphviz version 6.0.1 (20220911.1526)\n",
+       " -->\n",
+       "<!-- Pages: 1 -->\n",
+       "<svg width=\"459pt\" height=\"305pt\"\n",
+       " viewBox=\"0.00 0.00 458.83 305.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
+       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 301)\">\n",
+       "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-301 454.83,-301 454.83,4 -4,4\"/>\n",
+       "<!-- tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil))) -->\n",
+       "<g id=\"node1\" class=\"node\">\n",
+       "<title>tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"168.99\" cy=\"-279\" rx=\"168.97\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"168.99\" y=\"-275.3\" font-family=\"Times,serif\" font-size=\"14.00\">tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,a,nil) -->\n",
+       "<g id=\"node2\" class=\"node\">\n",
+       "<title>tree(nil,a,nil)</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"144.99\" cy=\"-105\" rx=\"57.39\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"144.99\" y=\"-101.3\" font-family=\"Times,serif\" font-size=\"14.00\">tree(nil,a,nil)</text>\n",
+       "</g>\n",
+       "<!-- tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))&#45;&gt;tree(nil,a,nil) -->\n",
+       "<g id=\"edge1\" class=\"edge\">\n",
+       "<title>tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))&#45;&gt;tree(nil,a,nil)</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M154.28,-260.89C144.13,-247.89 131.5,-229.05 125.99,-210 118.49,-184.13 125.83,-153.74 133.46,-132.52\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"136.73,-133.77 137.05,-123.18 130.2,-131.26 136.73,-133.77\"/>\n",
+       "<text text-anchor=\"middle\" x=\"129.49\" y=\"-188.3\" font-family=\"Times,serif\" font-size=\"14.00\">1</text>\n",
+       "</g>\n",
+       "<!-- b -->\n",
+       "<g id=\"node3\" class=\"node\">\n",
+       "<title>b</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"168.99\" cy=\"-192\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"168.99\" y=\"-188.3\" font-family=\"Times,serif\" font-size=\"14.00\">b</text>\n",
+       "</g>\n",
+       "<!-- tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))&#45;&gt;b -->\n",
+       "<g id=\"edge2\" class=\"edge\">\n",
+       "<title>tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))&#45;&gt;b</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M168.99,-260.8C168.99,-249.16 168.99,-233.55 168.99,-220.24\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"172.49,-220.18 168.99,-210.18 165.49,-220.18 172.49,-220.18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"172.49\" y=\"-231.8\" font-family=\"Times,serif\" font-size=\"14.00\">2</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,c,tree(nil,d,nil)) -->\n",
+       "<g id=\"node4\" class=\"node\">\n",
+       "<title>tree(nil,c,tree(nil,d,nil))</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"308.99\" cy=\"-192\" rx=\"94.78\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"308.99\" y=\"-188.3\" font-family=\"Times,serif\" font-size=\"14.00\">tree(nil,c,tree(nil,d,nil))</text>\n",
+       "</g>\n",
+       "<!-- tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))&#45;&gt;tree(nil,c,tree(nil,d,nil)) -->\n",
+       "<g id=\"edge3\" class=\"edge\">\n",
+       "<title>tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))&#45;&gt;tree(nil,c,tree(nil,d,nil))</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M196.64,-261.21C218.55,-247.91 249.31,-229.23 273.11,-214.78\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"275.13,-217.65 281.86,-209.47 271.5,-211.67 275.13,-217.65\"/>\n",
+       "<text text-anchor=\"middle\" x=\"250.49\" y=\"-231.8\" font-family=\"Times,serif\" font-size=\"14.00\">3</text>\n",
+       "</g>\n",
+       "<!-- nil -->\n",
+       "<g id=\"node5\" class=\"node\">\n",
+       "<title>nil</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"237.99\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"237.99\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">nil</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,a,nil)&#45;&gt;nil -->\n",
+       "<g id=\"edge4\" class=\"edge\">\n",
+       "<title>tree(nil,a,nil)&#45;&gt;nil</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M156.03,-87.08C163.24,-76.8 173.27,-63.82 183.99,-54 191.5,-47.11 200.53,-40.68 209.03,-35.27\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"210.91,-38.22 217.61,-30.01 207.25,-32.25 210.91,-38.22\"/>\n",
+       "<text text-anchor=\"middle\" x=\"187.49\" y=\"-57.8\" font-family=\"Times,serif\" font-size=\"14.00\">1</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,a,nil)&#45;&gt;nil -->\n",
+       "<g id=\"edge6\" class=\"edge\">\n",
+       "<title>tree(nil,a,nil)&#45;&gt;nil</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M167.11,-88.33C174.88,-82.53 183.53,-75.72 190.99,-69 200.43,-60.49 210.17,-50.38 218.32,-41.49\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"220.92,-43.83 225.02,-34.06 215.72,-39.14 220.92,-43.83\"/>\n",
+       "<text text-anchor=\"middle\" x=\"208.49\" y=\"-57.8\" font-family=\"Times,serif\" font-size=\"14.00\">3</text>\n",
+       "</g>\n",
+       "<!-- a -->\n",
+       "<g id=\"node6\" class=\"node\">\n",
+       "<title>a</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"144.99\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"144.99\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">a</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,a,nil)&#45;&gt;a -->\n",
+       "<g id=\"edge5\" class=\"edge\">\n",
+       "<title>tree(nil,a,nil)&#45;&gt;a</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M144.99,-86.8C144.99,-75.16 144.99,-59.55 144.99,-46.24\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"148.49,-46.18 144.99,-36.18 141.49,-46.18 148.49,-46.18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"148.49\" y=\"-57.8\" font-family=\"Times,serif\" font-size=\"14.00\">2</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,c,tree(nil,d,nil))&#45;&gt;nil -->\n",
+       "<g id=\"edge7\" class=\"edge\">\n",
+       "<title>tree(nil,c,tree(nil,d,nil))&#45;&gt;nil</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M287.86,-174.39C273.66,-161.9 255.96,-143.49 246.99,-123 236.29,-98.57 234.91,-67.87 235.68,-46.17\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"239.18,-46.19 236.22,-36.02 232.19,-45.82 239.18,-46.19\"/>\n",
+       "<text text-anchor=\"middle\" x=\"250.49\" y=\"-101.3\" font-family=\"Times,serif\" font-size=\"14.00\">1</text>\n",
+       "</g>\n",
+       "<!-- c -->\n",
+       "<g id=\"node7\" class=\"node\">\n",
+       "<title>c</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"289.99\" cy=\"-105\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"289.99\" y=\"-101.3\" font-family=\"Times,serif\" font-size=\"14.00\">c</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,c,tree(nil,d,nil))&#45;&gt;c -->\n",
+       "<g id=\"edge8\" class=\"edge\">\n",
+       "<title>tree(nil,c,tree(nil,d,nil))&#45;&gt;c</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M303.76,-174C302.11,-168.31 300.36,-161.91 298.99,-156 297.28,-148.64 295.7,-140.61 294.37,-133.18\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"297.8,-132.47 292.65,-123.21 290.9,-133.66 297.8,-132.47\"/>\n",
+       "<text text-anchor=\"middle\" x=\"302.49\" y=\"-144.8\" font-family=\"Times,serif\" font-size=\"14.00\">2</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,d,nil) -->\n",
+       "<g id=\"node8\" class=\"node\">\n",
+       "<title>tree(nil,d,nil)</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"392.99\" cy=\"-105\" rx=\"57.69\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"392.99\" y=\"-101.3\" font-family=\"Times,serif\" font-size=\"14.00\">tree(nil,d,nil)</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,c,tree(nil,d,nil))&#45;&gt;tree(nil,d,nil) -->\n",
+       "<g id=\"edge9\" class=\"edge\">\n",
+       "<title>tree(nil,c,tree(nil,d,nil))&#45;&gt;tree(nil,d,nil)</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M325.58,-174.21C338.09,-161.55 355.41,-144.03 369.36,-129.91\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"372.17,-132.04 376.71,-122.47 367.19,-127.12 372.17,-132.04\"/>\n",
+       "<text text-anchor=\"middle\" x=\"359.49\" y=\"-144.8\" font-family=\"Times,serif\" font-size=\"14.00\">3</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,d,nil)&#45;&gt;nil -->\n",
+       "<g id=\"edge10\" class=\"edge\">\n",
+       "<title>tree(nil,d,nil)&#45;&gt;nil</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M361.27,-89.94C348.03,-83.83 332.6,-76.39 318.99,-69 300.65,-59.05 280.71,-46.75 265.19,-36.85\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"266.92,-33.8 256.62,-31.32 263.13,-39.68 266.92,-33.8\"/>\n",
+       "<text text-anchor=\"middle\" x=\"322.49\" y=\"-57.8\" font-family=\"Times,serif\" font-size=\"14.00\">1</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,d,nil)&#45;&gt;nil -->\n",
+       "<g id=\"edge12\" class=\"edge\">\n",
+       "<title>tree(nil,d,nil)&#45;&gt;nil</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M374.26,-87.92C361.31,-77.34 343.34,-63.7 325.99,-54 308.71,-44.34 288.22,-36.03 271.37,-29.93\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"272.51,-26.62 261.91,-26.6 270.18,-33.22 272.51,-26.62\"/>\n",
+       "<text text-anchor=\"middle\" x=\"352.49\" y=\"-57.8\" font-family=\"Times,serif\" font-size=\"14.00\">3</text>\n",
+       "</g>\n",
+       "<!-- d -->\n",
+       "<g id=\"node9\" class=\"node\">\n",
+       "<title>d</title>\n",
+       "<ellipse fill=\"none\" stroke=\"black\" cx=\"392.99\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"392.99\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">d</text>\n",
+       "</g>\n",
+       "<!-- tree(nil,d,nil)&#45;&gt;d -->\n",
+       "<g id=\"edge11\" class=\"edge\">\n",
+       "<title>tree(nil,d,nil)&#45;&gt;d</title>\n",
+       "<path fill=\"none\" stroke=\"black\" d=\"M392.99,-86.8C392.99,-75.16 392.99,-59.55 392.99,-46.24\"/>\n",
+       "<polygon fill=\"black\" stroke=\"black\" points=\"396.49,-46.18 392.99,-36.18 389.49,-46.18 396.49,-46.18\"/>\n",
+       "<text text-anchor=\"middle\" x=\"396.49\" y=\"-57.8\" font-family=\"Times,serif\" font-size=\"14.00\">2</text>\n",
+       "</g>\n",
+       "</g>\n",
+       "</svg>\n"
+      ],
+      "text/plain": [
+       "digraph {\n",
+       "    \"tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))\" -> \"tree(nil,a,nil)\" [label=\"1\"]\n",
+       "    \"tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))\" -> \"b\" [label=\"2\"]\n",
+       "    \"tree(tree(nil,a,nil),b,tree(nil,c,tree(nil,d,nil)))\" -> \"tree(nil,c,tree(nil,d,nil))\" [label=\"3\"]\n",
+       "    \"tree(nil,a,nil)\" -> \"nil\" [label=\"1\"]\n",
+       "    \"tree(nil,a,nil)\" -> \"a\" [label=\"2\"]\n",
+       "    \"tree(nil,a,nil)\" -> \"nil\" [label=\"3\"]\n",
+       "    \"tree(nil,c,tree(nil,d,nil))\" -> \"nil\" [label=\"1\"]\n",
+       "    \"tree(nil,c,tree(nil,d,nil))\" -> \"c\" [label=\"2\"]\n",
+       "    \"tree(nil,c,tree(nil,d,nil))\" -> \"tree(nil,d,nil)\" [label=\"3\"]\n",
+       "    \"tree(nil,d,nil)\" -> \"nil\" [label=\"1\"]\n",
+       "    \"tree(nil,d,nil)\" -> \"d\" [label=\"2\"]\n",
+       "    \"tree(nil,d,nil)\" -> \"nil\" [label=\"3\"]\n",
+       "}"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1mtrue"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "jupyter:print_transition_graph(subt/3, 1, 3,2)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f65812f1",
+   "metadata": {
+    "vscode": {
+     "languageId": "prolog"
+    }
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Prolog",
+   "language": "prolog",
+   "name": "prolog_kernel"
+  },
+  "language_info": {
+   "codemirror_mode": "prolog",
+   "file_extension": ".pl",
+   "mimetype": "text/x-prolog",
+   "name": "Prolog"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/logic_programming/2_IntroProlog.pdf b/logic_programming/2_IntroProlog.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..0f643d127e2c60779fd92797dfe125a7f1dde51a
Binary files /dev/null and b/logic_programming/2_IntroProlog.pdf differ