{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Knowledge Graphs for Complex Topics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction\n",
    "\n",
    "**What is a knowledge graph?**\n",
    "\n",
    "A knowledge graph, also known as a semantic network, represents real-world entities and their relationships. It consists of nodes, edges, and labels. Nodes can represent any entity, while edges define the connections between them. For example, a node representing an author like \"J.K. Rowling\" can be connected to another node representing one of her books, \"Harry Potter\", with the edge \"author of\".\n",
    "\n",
    "**Applications of knowledge graphs**\n",
    "\n",
    "Knowledge graphs have various applications, including:\n",
    "\n",
    "-  Search Engines: They enhance search results by incorporating semantic-search information from diverse sources.\n",
    "-  Recommendation Systems: They suggest products or services based on user behavior and preferences.\n",
    "-  Natural Language Processing: They aid in understanding and generating human language.\n",
    "-  Data Integration: They facilitate the integration of data from different sources by identifying relationships.\n",
    "-  Artificial Intelligence and Machine Learning: They provide contextual information to improve decision-making."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "----"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup and Dependencies"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Today, we're going to use the [`instructor`](https://github.com/jxnl/instructor) library to simplify the interaction between OpenAI and our code. Along with [Graphviz](https://graphviz.org) library to bring structure to our intricate subjects and have a graph visualization.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import instructor \n",
    "from openai import OpenAI\n",
    "\n",
    "client = instructor.patch(OpenAI())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Install the Graphviz based on your operation system https://graphviz.org/download/"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Node and Edge Classes\n",
    "\n",
    "We begin by modeling our knowledge graph with Node and Edge objects.\n",
    "\n",
    "Node objects represent key concepts or entities, while Edge objects signify the relationships between them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pydantic import BaseModel, Field\n",
    "from typing import List, Optional\n",
    "\n",
    "class Node(BaseModel):\n",
    "    id: int\n",
    "    label: str\n",
    "    color: str\n",
    "\n",
    "class Edge(BaseModel):\n",
    "    source: int\n",
    "    target: int\n",
    "    label: str\n",
    "    color: str = \"black\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `KnowledgeGraph` Class"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `KnowledgeGraph` class combines nodes and edges to create a comprehensive graph structure. It includes lists of nodes and edges, where each node represents a key concept or entity, and each edge represents a relationship between two nodes.\n",
    "\n",
    "Later on, you'll see that we designed this class to match the graph object in the graphviz library, which makes it easier to visualize our graph.\n",
    "\n",
    "The `visualize_knowledge_graph` function is used to visualize a knowledge graph. It takes a `KnowledgeGraph` object as input, which contains nodes and edges. The function utilizes the `graphviz` library to generate a directed graph (`Digraph`). Each node and edge from the `KnowledgeGraph` is added to the `Digraph` with their respective attributes (id, label, color). Finally, the graph is rendered and displayed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from graphviz import Digraph\n",
    "from IPython.display import display\n",
    "\n",
    "class KnowledgeGraph(BaseModel):\n",
    "    nodes: List[Node] = Field(..., default_factory=list)  # A list of nodes in the knowledge graph.\n",
    "    edges: List[Edge] = Field(..., default_factory=list)  # A list of edges in the knowledge graph.\n",
    "\n",
    "\n",
    "    def visualize_knowledge_graph(self):\n",
    "        dot = Digraph(comment=\"Knowledge Graph\")\n",
    "\n",
    "        for node in self.nodes:\n",
    "            dot.node(name=str(node.id), label=node.label, color=node.color)\n",
    "        for edge in self.edges:\n",
    "            dot.edge(str(edge.source), str(edge.target), label=edge.label, color=edge.color)\n",
    "        \n",
    "        return display(dot)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generating the Knowledge Graph\n",
    "\n",
    "### generate_graph function\n",
    "\n",
    "The ``generate_graph`` function uses OpenAI's model to create a KnowledgeGraph object from an input string.\n",
    "\n",
    "It requests the model to interpret the input as a detailed knowledge graph and uses the response to form the KnowledgeGraph object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_graph(input) -> KnowledgeGraph:\n",
    "    return client.chat.completions.create(\n",
    "        model=\"gpt-4-1106-preview\",\n",
    "        messages=[\n",
    "            {\n",
    "                \"role\": \"user\",\n",
    "                \"content\": f\"Help me understand the following by describing it as small knowledge graph: {input}\",\n",
    "            }\n",
    "        ],\n",
    "        response_model=KnowledgeGraph,\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "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 9.0.0 (20230911.1827)\n",
       " -->\n",
       "<!-- Pages: 1 -->\n",
       "<svg width=\"1303pt\" height=\"133pt\"\n",
       " viewBox=\"0.00 0.00 1303.11 132.50\" 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 128.5)\">\n",
       "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-128.5 1299.11,-128.5 1299.11,4 -4,4\"/>\n",
       "<!-- 1 -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>1</title>\n",
       "<ellipse fill=\"none\" stroke=\"blue\" cx=\"633.01\" cy=\"-106.5\" rx=\"88.71\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"633.01\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Quantum Mechanics</text>\n",
       "</g>\n",
       "<!-- 2 -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>2</title>\n",
       "<ellipse fill=\"none\" stroke=\"green\" cx=\"80.01\" cy=\"-18\" rx=\"80.01\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"80.01\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Quantum Particles</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;2 -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>1&#45;&gt;2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M558.22,-96.54C504.74,-89.92 431.09,-80.38 366.51,-70.5 278.43,-57.03 256.67,-52.03 169.01,-36 163.02,-34.9 156.8,-33.75 150.56,-32.58\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"151.31,-29.16 140.84,-30.75 150.02,-36.04 151.31,-29.16\"/>\n",
       "<text text-anchor=\"middle\" x=\"385.76\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">studies</text>\n",
       "</g>\n",
       "<!-- 3 -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>3</title>\n",
       "<ellipse fill=\"none\" stroke=\"green\" cx=\"272.01\" cy=\"-18\" rx=\"93.83\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"272.01\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Wave&#45;Particle Duality</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;3 -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>1&#45;&gt;3</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M573.16,-92.84C543.25,-86.39 506.54,-78.28 473.76,-70.5 427.73,-59.57 376.03,-46.35 336.49,-36.05\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"337.44,-32.68 326.88,-33.54 335.67,-39.45 337.44,-32.68\"/>\n",
       "<text text-anchor=\"middle\" x=\"499.14\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">describes</text>\n",
       "</g>\n",
       "<!-- 4 -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>4</title>\n",
       "<ellipse fill=\"none\" stroke=\"green\" cx=\"454.01\" cy=\"-18\" rx=\"70.29\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"454.01\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Quantum States</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;4 -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>1&#45;&gt;4</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M599.76,-89.43C570.51,-75.3 527.79,-54.65 496.15,-39.36\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"497.77,-36.26 487.24,-35.06 494.72,-42.56 497.77,-36.26\"/>\n",
       "<text text-anchor=\"middle\" x=\"582.89\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">involves</text>\n",
       "</g>\n",
       "<!-- 5 -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>5</title>\n",
       "<ellipse fill=\"none\" stroke=\"green\" cx=\"633.01\" cy=\"-18\" rx=\"90.25\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"633.01\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Uncertainty Principle</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;5 -->\n",
       "<g id=\"edge4\" class=\"edge\">\n",
       "<title>1&#45;&gt;5</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M633.01,-88.41C633.01,-76.76 633.01,-61.05 633.01,-47.52\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"636.51,-47.86 633.01,-37.86 629.51,-47.86 636.51,-47.86\"/>\n",
       "<text text-anchor=\"middle\" x=\"661.14\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">introduces</text>\n",
       "</g>\n",
       "<!-- 6 -->\n",
       "<g id=\"node6\" class=\"node\">\n",
       "<title>6</title>\n",
       "<ellipse fill=\"none\" stroke=\"green\" cx=\"838.01\" cy=\"-18\" rx=\"96.9\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"838.01\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Schrodinger&#39;s Equation</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;6 -->\n",
       "<g id=\"edge5\" class=\"edge\">\n",
       "<title>1&#45;&gt;6</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M670.14,-89.84C703.64,-75.7 753.13,-54.82 789.7,-39.39\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"790.88,-42.69 798.73,-35.58 788.16,-36.24 790.88,-42.69\"/>\n",
       "<text text-anchor=\"middle\" x=\"782.89\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">defined by</text>\n",
       "</g>\n",
       "<!-- 7 -->\n",
       "<g id=\"node7\" class=\"node\">\n",
       "<title>7</title>\n",
       "<ellipse fill=\"none\" stroke=\"green\" cx=\"1053.01\" cy=\"-18\" rx=\"99.97\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"1053.01\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Quantum Entanglement</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;7 -->\n",
       "<g id=\"edge6\" class=\"edge\">\n",
       "<title>1&#45;&gt;7</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M697.03,-93.66C732.19,-87.06 776.56,-78.56 816.01,-70.5 871.58,-59.15 934.29,-45.49 981.24,-35.09\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"981.73,-38.56 990.74,-32.98 980.22,-31.73 981.73,-38.56\"/>\n",
       "<text text-anchor=\"middle\" x=\"916.39\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">predicts</text>\n",
       "</g>\n",
       "<!-- 8 -->\n",
       "<g id=\"node8\" class=\"node\">\n",
       "<title>8</title>\n",
       "<ellipse fill=\"none\" stroke=\"green\" cx=\"1233.01\" cy=\"-18\" rx=\"62.1\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"1233.01\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Superposition</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;8 -->\n",
       "<g id=\"edge7\" class=\"edge\">\n",
       "<title>1&#45;&gt;8</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M712.85,-98.26C816.88,-88.08 1004.13,-67.23 1162.01,-36 1166.63,-35.09 1171.4,-34.08 1176.18,-33.03\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"1176.84,-36.47 1185.82,-30.84 1175.3,-29.64 1176.84,-36.47\"/>\n",
       "<text text-anchor=\"middle\" x=\"1075.14\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">introduces</text>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<graphviz.graphs.Digraph at 0x106e7f650>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "generate_graph(\"Explain quantum mechanics\").visualize_knowledge_graph()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Advanced: Accumulating Knowledge Graphs\n",
    "\n",
    "When dealing with larger datasets, or knowledge that grows over time, processing them all at once can be challenging due to limitations in prompt length or the complexity of the content. In such cases, an iterative approach to building the knowledge graph can be beneficial. This method involves processing the text in smaller, manageable chunks and updating the graph with new information from each chunk.\n",
    "\n",
    "### What are the benefits of this approach?\n",
    "\n",
    "-  Scalability: This approach can handle large datasets by breaking them down into smaller, more manageable pieces.\n",
    "\n",
    "-  Flexibility: It allows for dynamic updates to the graph, accommodating new information as it becomes available.\n",
    "\n",
    "-  Efficiency: Processing smaller chunks of text can be more efficient and less prone to errors or omissions."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### What has changed?\n",
    "\n",
    "The previous example provided a basic structure, while this new example introduces additional complexity and functionality. The Node and Edge classes now have a __hash__ method, allowing them to be used in sets and simplifying duplicate handling.\n",
    "\n",
    "The KnowledgeGraph class has been enhanced with two new methods: ``update`` and ``draw``.\n",
    "\n",
    "In the KnowledgeGraph class, the nodes and edges fields are now optional, offering greater flexibility.\n",
    "\n",
    "The ``update`` method enables the merging and removal of duplicates from two graphs.\n",
    "\n",
    "The ``draw`` method includes a prefix parameter, making it easier to create different graph versions during iterations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Node(BaseModel):\n",
    "    id: int\n",
    "    label: str\n",
    "    color: str\n",
    "\n",
    "    def __hash__(self) -> int:\n",
    "        return hash((id, self.label))\n",
    "    \n",
    "class Edge(BaseModel):\n",
    "    source: int\n",
    "    target: int\n",
    "    label: str\n",
    "    color: str = \"black\"\n",
    "\n",
    "    def __hash__(self) -> int:\n",
    "        return hash((self.source, self.target, self.label))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "class KnowledgeGraph(BaseModel):\n",
    "    # Optional list of nodes and edges in the knowledge graph\n",
    "    nodes: Optional[List[Node]] = Field(..., default_factory=list)\n",
    "    edges: Optional[List[Edge]] = Field(..., default_factory=list)\n",
    "\n",
    "    def update(self, other: \"KnowledgeGraph\") -> \"KnowledgeGraph\":\n",
    "        # This method updates the current graph with the other graph, deduplicating nodes and edges.\n",
    "        return KnowledgeGraph(\n",
    "            nodes=list(set(self.nodes + other.nodes)),  # Combine and deduplicate nodes\n",
    "            edges=list(set(self.edges + other.edges)),  # Combine and deduplicate edges\n",
    "        )\n",
    "    \n",
    "\n",
    "    def visualize_knowledge_graph(self):\n",
    "        dot = Digraph(comment=\"Knowledge Graph\")\n",
    "\n",
    "        for node in self.nodes:\n",
    "            dot.node(str(node.id), node.label, color=node.color)\n",
    "        for edge in self.edges:\n",
    "            dot.edge(str(edge.source), str(edge.target), label=edge.label, color=edge.color)\n",
    "        \n",
    "        return display(dot)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Generate iterative graphs\n",
    "\n",
    "The updated `generate_graph` function is specifically designed to handle a list of inputs iteratively. It updates the graph with each new piece of information.\n",
    "\n",
    "Upon closer inspection, this pattern resembles a common programming technique known as a \"reduce\" or \"fold\" function. A simple example of this would be iterating over a list to find the sum of all the elements squared.\n",
    "\n",
    "Here's an example in Python:\n",
    "\n",
    "```python\n",
    "cur_state = 0\n",
    "for i in [1, 2, 3, 4, 5]:\n",
    "    cur_state += i**2\n",
    "print(cur_state)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_graph(input: List[str]) -> KnowledgeGraph:\n",
    "    # Initialize an empty KnowledgeGraph\n",
    "    cur_state = KnowledgeGraph()\n",
    "\n",
    "    # Iterate over the input list\n",
    "    for i, inp in enumerate(input):\n",
    "        new_updates = client.chat.completions.create(\n",
    "            model=\"gpt-4-1106-preview\",\n",
    "            messages=[\n",
    "                {\n",
    "                    \"role\": \"system\",\n",
    "                    \"content\": \"\"\"You are an iterative knowledge graph builder.\n",
    "                    You are given the current state of the graph, and you must append the nodes and edges \n",
    "                    to it Do not procide any duplcates and try to reuse nodes as much as possible.\"\"\",\n",
    "                },\n",
    "                {\n",
    "                    \"role\": \"user\",\n",
    "                    \"content\": f\"\"\"Extract any new nodes and edges from the following:\n",
    "                    # Part {i}/{len(input)} of the input:\n",
    "\n",
    "                    {inp}\"\"\",\n",
    "                },\n",
    "                {\n",
    "                    \"role\": \"user\",\n",
    "                    \"content\": f\"\"\"Here is the current state of the graph:\n",
    "                    {cur_state.model_dump_json(indent=2)}\"\"\",\n",
    "                },\n",
    "            ],\n",
    "            response_model=KnowledgeGraph,\n",
    "        )  # type: ignore\n",
    "\n",
    "        # Update the current state with the new updates\n",
    "        cur_state = cur_state.update(new_updates)\n",
    "\n",
    "        # Draw the current state of the graph\n",
    "        cur_state.visualize_knowledge_graph() \n",
    "        \n",
    "    # Return the final state of the KnowledgeGraph\n",
    "    return cur_state\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Examples Use Case"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this approach, we process the text in manageable chunks, one at a time.\n",
    "\n",
    "This method is particularly beneficial when dealing with extensive text that may not fit into a single prompt.\n",
    "\n",
    "It is especially useful in scenarios such as constructing a knowledge graph for a complex topic, where the information is distributed across multiple documents or sections."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "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 9.0.0 (20230911.1827)\n",
       " -->\n",
       "<!-- Pages: 1 -->\n",
       "<svg width=\"401pt\" height=\"133pt\"\n",
       " viewBox=\"0.00 0.00 400.90 132.50\" 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 128.5)\">\n",
       "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-128.5 396.9,-128.5 396.9,4 -4,4\"/>\n",
       "<!-- 3 -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>3</title>\n",
       "<ellipse fill=\"none\" stroke=\"orange\" cx=\"44.19\" cy=\"-18\" rx=\"44.19\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"44.19\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Physicist</text>\n",
       "</g>\n",
       "<!-- 4 -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>4</title>\n",
       "<ellipse fill=\"none\" stroke=\"red\" cx=\"152.19\" cy=\"-18\" rx=\"45.72\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"152.19\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Professor</text>\n",
       "</g>\n",
       "<!-- 1 -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>1</title>\n",
       "<ellipse fill=\"none\" stroke=\"blue\" cx=\"152.19\" cy=\"-106.5\" rx=\"31.39\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"152.19\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Jason</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;3 -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>1&#45;&gt;3</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M134.35,-91.22C117.49,-77.71 91.92,-57.23 72.32,-41.53\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"74.68,-38.94 64.69,-35.42 70.3,-44.4 74.68,-38.94\"/>\n",
       "<text text-anchor=\"middle\" x=\"112.69\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">is</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;4 -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>1&#45;&gt;4</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M152.19,-88.41C152.19,-76.76 152.19,-61.05 152.19,-47.52\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"155.69,-47.86 152.19,-37.86 148.69,-47.86 155.69,-47.86\"/>\n",
       "<text text-anchor=\"middle\" x=\"156.69\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">is</text>\n",
       "</g>\n",
       "<!-- 2 -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>2</title>\n",
       "<ellipse fill=\"none\" stroke=\"green\" cx=\"304.19\" cy=\"-18\" rx=\"88.71\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"304.19\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Quantum Mechanics</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;2 -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>1&#45;&gt;2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M173.96,-93.11C197.83,-79.53 236.58,-57.47 265.61,-40.95\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"267.16,-44.1 274.12,-36.11 263.7,-38.01 267.16,-44.1\"/>\n",
       "<text text-anchor=\"middle\" x=\"276.69\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">knows about</text>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<graphviz.graphs.Digraph at 0x129342f10>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "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 9.0.0 (20230911.1827)\n",
       " -->\n",
       "<!-- Pages: 1 -->\n",
       "<svg width=\"401pt\" height=\"221pt\"\n",
       " viewBox=\"0.00 0.00 400.90 221.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 217)\">\n",
       "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-217 396.9,-217 396.9,4 -4,4\"/>\n",
       "<!-- 3 -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>3</title>\n",
       "<ellipse fill=\"none\" stroke=\"orange\" cx=\"44.19\" cy=\"-106.5\" rx=\"44.19\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"44.19\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Physicist</text>\n",
       "</g>\n",
       "<!-- 5 -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>5</title>\n",
       "<ellipse fill=\"none\" stroke=\"yellow\" cx=\"152.19\" cy=\"-18\" rx=\"33.44\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"152.19\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Smart</text>\n",
       "</g>\n",
       "<!-- 4 -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>4</title>\n",
       "<ellipse fill=\"none\" stroke=\"red\" cx=\"152.19\" cy=\"-106.5\" rx=\"45.72\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"152.19\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Professor</text>\n",
       "</g>\n",
       "<!-- 4&#45;&gt;5 -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>4&#45;&gt;5</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M152.19,-88.41C152.19,-76.76 152.19,-61.05 152.19,-47.52\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"155.69,-47.86 152.19,-37.86 148.69,-47.86 155.69,-47.86\"/>\n",
       "<text text-anchor=\"middle\" x=\"160.44\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">are</text>\n",
       "</g>\n",
       "<!-- 1 -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>1</title>\n",
       "<ellipse fill=\"none\" stroke=\"blue\" cx=\"152.19\" cy=\"-195\" rx=\"31.39\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"152.19\" y=\"-189.95\" font-family=\"Times,serif\" font-size=\"14.00\">Jason</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;3 -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>1&#45;&gt;3</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M134.35,-179.72C117.49,-166.21 91.92,-145.73 72.32,-130.03\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"74.68,-127.44 64.69,-123.92 70.3,-132.9 74.68,-127.44\"/>\n",
       "<text text-anchor=\"middle\" x=\"112.69\" y=\"-145.7\" font-family=\"Times,serif\" font-size=\"14.00\">is</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;4 -->\n",
       "<g id=\"edge4\" class=\"edge\">\n",
       "<title>1&#45;&gt;4</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M152.19,-176.91C152.19,-165.26 152.19,-149.55 152.19,-136.02\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"155.69,-136.36 152.19,-126.36 148.69,-136.36 155.69,-136.36\"/>\n",
       "<text text-anchor=\"middle\" x=\"156.69\" y=\"-145.7\" font-family=\"Times,serif\" font-size=\"14.00\">is</text>\n",
       "</g>\n",
       "<!-- 2 -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>2</title>\n",
       "<ellipse fill=\"none\" stroke=\"green\" cx=\"304.19\" cy=\"-106.5\" rx=\"88.71\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"304.19\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Quantum Mechanics</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;2 -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>1&#45;&gt;2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M173.96,-181.61C197.83,-168.03 236.58,-145.97 265.61,-129.45\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"267.16,-132.6 274.12,-124.61 263.7,-126.51 267.16,-132.6\"/>\n",
       "<text text-anchor=\"middle\" x=\"276.69\" y=\"-145.7\" font-family=\"Times,serif\" font-size=\"14.00\">knows about</text>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<graphviz.graphs.Digraph at 0x1293494d0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "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 9.0.0 (20230911.1827)\n",
       " -->\n",
       "<!-- Pages: 1 -->\n",
       "<svg width=\"468pt\" height=\"310pt\"\n",
       " viewBox=\"0.00 0.00 467.78 309.50\" 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 305.5)\">\n",
       "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-305.5 463.78,-305.5 463.78,4 -4,4\"/>\n",
       "<!-- 3 -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>3</title>\n",
       "<ellipse fill=\"none\" stroke=\"orange\" cx=\"220.07\" cy=\"-106.5\" rx=\"44.19\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"220.07\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Physicist</text>\n",
       "</g>\n",
       "<!-- 6 -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>6</title>\n",
       "<ellipse fill=\"none\" stroke=\"pink\" cx=\"114.07\" cy=\"-283.5\" rx=\"31.9\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"114.07\" y=\"-278.45\" font-family=\"Times,serif\" font-size=\"14.00\">Sarah</text>\n",
       "</g>\n",
       "<!-- 7 -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>7</title>\n",
       "<ellipse fill=\"none\" stroke=\"purple\" cx=\"39.07\" cy=\"-195\" rx=\"39.07\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"39.07\" y=\"-189.95\" font-family=\"Times,serif\" font-size=\"14.00\">Student</text>\n",
       "</g>\n",
       "<!-- 6&#45;&gt;7 -->\n",
       "<g id=\"edge7\" class=\"edge\">\n",
       "<title>6&#45;&gt;7</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M100.66,-267.04C89.46,-254.12 73.29,-235.47 60.32,-220.51\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"63.31,-218.62 54.12,-213.35 58.02,-223.2 63.31,-218.62\"/>\n",
       "<text text-anchor=\"middle\" x=\"88.57\" y=\"-234.2\" font-family=\"Times,serif\" font-size=\"14.00\">is</text>\n",
       "</g>\n",
       "<!-- 4 -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>4</title>\n",
       "<ellipse fill=\"none\" stroke=\"red\" cx=\"112.07\" cy=\"-106.5\" rx=\"45.72\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"112.07\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Professor</text>\n",
       "</g>\n",
       "<!-- 6&#45;&gt;4 -->\n",
       "<g id=\"edge6\" class=\"edge\">\n",
       "<title>6&#45;&gt;4</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M113.87,-265.08C113.52,-234.94 112.81,-172.8 112.4,-136.2\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"115.9,-136.32 112.28,-126.36 108.9,-136.4 115.9,-136.32\"/>\n",
       "<text text-anchor=\"middle\" x=\"141.07\" y=\"-189.95\" font-family=\"Times,serif\" font-size=\"14.00\">student of</text>\n",
       "</g>\n",
       "<!-- 1 -->\n",
       "<g id=\"node6\" class=\"node\">\n",
       "<title>1</title>\n",
       "<ellipse fill=\"none\" stroke=\"blue\" cx=\"219.07\" cy=\"-195\" rx=\"31.39\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"219.07\" y=\"-189.95\" font-family=\"Times,serif\" font-size=\"14.00\">Jason</text>\n",
       "</g>\n",
       "<!-- 6&#45;&gt;1 -->\n",
       "<g id=\"edge5\" class=\"edge\">\n",
       "<title>6&#45;&gt;1</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M131.41,-268.22C148.13,-254.44 173.65,-233.42 192.85,-217.6\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"195.04,-220.33 200.54,-211.27 190.59,-214.92 195.04,-220.33\"/>\n",
       "<text text-anchor=\"middle\" x=\"193.69\" y=\"-234.2\" font-family=\"Times,serif\" font-size=\"14.00\">knows</text>\n",
       "</g>\n",
       "<!-- 5 -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>5</title>\n",
       "<ellipse fill=\"none\" stroke=\"yellow\" cx=\"112.07\" cy=\"-18\" rx=\"33.44\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"112.07\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Smart</text>\n",
       "</g>\n",
       "<!-- 4&#45;&gt;5 -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>4&#45;&gt;5</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M112.07,-88.41C112.07,-76.76 112.07,-61.05 112.07,-47.52\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"115.57,-47.86 112.07,-37.86 108.57,-47.86 115.57,-47.86\"/>\n",
       "<text text-anchor=\"middle\" x=\"120.32\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">are</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;3 -->\n",
       "<g id=\"edge4\" class=\"edge\">\n",
       "<title>1&#45;&gt;3</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M219.27,-176.91C219.4,-165.26 219.58,-149.55 219.74,-136.02\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"223.23,-136.4 219.85,-126.36 216.23,-136.32 223.23,-136.4\"/>\n",
       "<text text-anchor=\"middle\" x=\"224.57\" y=\"-145.7\" font-family=\"Times,serif\" font-size=\"14.00\">is</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;4 -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>1&#45;&gt;4</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M201.4,-179.72C184.8,-166.29 159.67,-145.99 140.3,-130.32\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"142.73,-127.79 132.75,-124.22 138.33,-133.23 142.73,-127.79\"/>\n",
       "<text text-anchor=\"middle\" x=\"180.57\" y=\"-145.7\" font-family=\"Times,serif\" font-size=\"14.00\">is</text>\n",
       "</g>\n",
       "<!-- 2 -->\n",
       "<g id=\"node7\" class=\"node\">\n",
       "<title>2</title>\n",
       "<ellipse fill=\"none\" stroke=\"green\" cx=\"371.07\" cy=\"-106.5\" rx=\"88.71\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"371.07\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Quantum Mechanics</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;2 -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>1&#45;&gt;2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M240.85,-181.61C264.71,-168.03 303.46,-145.97 332.5,-129.45\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"334.04,-132.6 341,-124.61 330.58,-126.51 334.04,-132.6\"/>\n",
       "<text text-anchor=\"middle\" x=\"342.57\" y=\"-145.7\" font-family=\"Times,serif\" font-size=\"14.00\">knows about</text>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<graphviz.graphs.Digraph at 0x128ff4d50>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "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 9.0.0 (20230911.1827)\n",
       " -->\n",
       "<!-- Pages: 1 -->\n",
       "<svg width=\"669pt\" height=\"310pt\"\n",
       " viewBox=\"0.00 0.00 669.50 309.50\" 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 305.5)\">\n",
       "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-305.5 665.5,-305.5 665.5,4 -4,4\"/>\n",
       "<!-- 3 -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>3</title>\n",
       "<ellipse fill=\"none\" stroke=\"orange\" cx=\"421.78\" cy=\"-106.5\" rx=\"44.19\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"421.78\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Physicist</text>\n",
       "</g>\n",
       "<!-- 9 -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>9</title>\n",
       "<ellipse fill=\"none\" stroke=\"red\" cx=\"91.78\" cy=\"-106.5\" rx=\"38.56\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"91.78\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Canada</text>\n",
       "</g>\n",
       "<!-- 8 -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>8</title>\n",
       "<ellipse fill=\"none\" stroke=\"blue\" cx=\"91.78\" cy=\"-195\" rx=\"91.78\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"91.78\" y=\"-189.95\" font-family=\"Times,serif\" font-size=\"14.00\">University of Toronto</text>\n",
       "</g>\n",
       "<!-- 8&#45;&gt;9 -->\n",
       "<g id=\"edge8\" class=\"edge\">\n",
       "<title>8&#45;&gt;9</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M91.78,-176.91C91.78,-165.26 91.78,-149.55 91.78,-136.02\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"95.28,-136.36 91.78,-126.36 88.28,-136.36 95.28,-136.36\"/>\n",
       "<text text-anchor=\"middle\" x=\"103.41\" y=\"-145.7\" font-family=\"Times,serif\" font-size=\"14.00\">is in</text>\n",
       "</g>\n",
       "<!-- 6 -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>6</title>\n",
       "<ellipse fill=\"none\" stroke=\"pink\" cx=\"277.78\" cy=\"-283.5\" rx=\"31.9\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"277.78\" y=\"-278.45\" font-family=\"Times,serif\" font-size=\"14.00\">Sarah</text>\n",
       "</g>\n",
       "<!-- 6&#45;&gt;8 -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>6&#45;&gt;8</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M253.3,-271.58C238.02,-264.74 217.97,-255.69 200.28,-247.5 178.95,-237.62 155.37,-226.46 135.65,-217.05\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"137.33,-213.98 126.8,-212.82 134.31,-220.29 137.33,-213.98\"/>\n",
       "<text text-anchor=\"middle\" x=\"227.03\" y=\"-234.2\" font-family=\"Times,serif\" font-size=\"14.00\">student at</text>\n",
       "</g>\n",
       "<!-- 7 -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>7</title>\n",
       "<ellipse fill=\"none\" stroke=\"purple\" cx=\"240.78\" cy=\"-195\" rx=\"39.07\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"240.78\" y=\"-189.95\" font-family=\"Times,serif\" font-size=\"14.00\">Student</text>\n",
       "</g>\n",
       "<!-- 6&#45;&gt;7 -->\n",
       "<g id=\"edge9\" class=\"edge\">\n",
       "<title>6&#45;&gt;7</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M270.65,-265.82C265.51,-253.81 258.47,-237.34 252.51,-223.41\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"255.77,-222.13 248.62,-214.31 249.33,-224.88 255.77,-222.13\"/>\n",
       "<text text-anchor=\"middle\" x=\"267.28\" y=\"-234.2\" font-family=\"Times,serif\" font-size=\"14.00\">is</text>\n",
       "</g>\n",
       "<!-- 4 -->\n",
       "<g id=\"node7\" class=\"node\">\n",
       "<title>4</title>\n",
       "<ellipse fill=\"none\" stroke=\"red\" cx=\"313.78\" cy=\"-106.5\" rx=\"45.72\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"313.78\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Professor</text>\n",
       "</g>\n",
       "<!-- 6&#45;&gt;4 -->\n",
       "<g id=\"edge7\" class=\"edge\">\n",
       "<title>6&#45;&gt;4</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M281.3,-265.4C287.5,-235.29 300.41,-172.53 307.95,-135.85\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"311.31,-136.91 309.89,-126.41 304.45,-135.5 311.31,-136.91\"/>\n",
       "<text text-anchor=\"middle\" x=\"326.78\" y=\"-189.95\" font-family=\"Times,serif\" font-size=\"14.00\">student of</text>\n",
       "</g>\n",
       "<!-- 1 -->\n",
       "<g id=\"node8\" class=\"node\">\n",
       "<title>1</title>\n",
       "<ellipse fill=\"none\" stroke=\"blue\" cx=\"420.78\" cy=\"-195\" rx=\"31.39\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"420.78\" y=\"-189.95\" font-family=\"Times,serif\" font-size=\"14.00\">Jason</text>\n",
       "</g>\n",
       "<!-- 6&#45;&gt;1 -->\n",
       "<g id=\"edge6\" class=\"edge\">\n",
       "<title>6&#45;&gt;1</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M298.88,-269.74C322.96,-255.17 362.56,-231.22 390.06,-214.58\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"391.56,-217.77 398.3,-209.6 387.93,-211.78 391.56,-217.77\"/>\n",
       "<text text-anchor=\"middle\" x=\"380.41\" y=\"-234.2\" font-family=\"Times,serif\" font-size=\"14.00\">knows</text>\n",
       "</g>\n",
       "<!-- 5 -->\n",
       "<g id=\"node6\" class=\"node\">\n",
       "<title>5</title>\n",
       "<ellipse fill=\"none\" stroke=\"yellow\" cx=\"313.78\" cy=\"-18\" rx=\"33.44\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"313.78\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">Smart</text>\n",
       "</g>\n",
       "<!-- 4&#45;&gt;5 -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>4&#45;&gt;5</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M313.78,-88.41C313.78,-76.76 313.78,-61.05 313.78,-47.52\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"317.28,-47.86 313.78,-37.86 310.28,-47.86 317.28,-47.86\"/>\n",
       "<text text-anchor=\"middle\" x=\"322.03\" y=\"-57.2\" font-family=\"Times,serif\" font-size=\"14.00\">are</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;3 -->\n",
       "<g id=\"edge5\" class=\"edge\">\n",
       "<title>1&#45;&gt;3</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M420.98,-176.91C421.12,-165.26 421.3,-149.55 421.45,-136.02\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"424.95,-136.4 421.57,-126.36 417.95,-136.32 424.95,-136.4\"/>\n",
       "<text text-anchor=\"middle\" x=\"426.28\" y=\"-145.7\" font-family=\"Times,serif\" font-size=\"14.00\">is</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;4 -->\n",
       "<g id=\"edge4\" class=\"edge\">\n",
       "<title>1&#45;&gt;4</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M403.12,-179.72C386.51,-166.29 361.39,-145.99 342.01,-130.32\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"344.45,-127.79 334.47,-124.22 340.05,-133.23 344.45,-127.79\"/>\n",
       "<text text-anchor=\"middle\" x=\"382.28\" y=\"-145.7\" font-family=\"Times,serif\" font-size=\"14.00\">is</text>\n",
       "</g>\n",
       "<!-- 2 -->\n",
       "<g id=\"node9\" class=\"node\">\n",
       "<title>2</title>\n",
       "<ellipse fill=\"none\" stroke=\"green\" cx=\"572.78\" cy=\"-106.5\" rx=\"88.71\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"572.78\" y=\"-101.45\" font-family=\"Times,serif\" font-size=\"14.00\">Quantum Mechanics</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;2 -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>1&#45;&gt;2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M442.56,-181.61C466.43,-168.03 505.18,-145.97 534.21,-129.45\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"535.76,-132.6 542.72,-124.61 532.3,-126.51 535.76,-132.6\"/>\n",
       "<text text-anchor=\"middle\" x=\"545.28\" y=\"-145.7\" font-family=\"Times,serif\" font-size=\"14.00\">knows about</text>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<graphviz.graphs.Digraph at 0x129349610>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "text_chunks = [\n",
    "    \"Jason knows a lot about quantum mechanics. He is a physicist. He is a professor\",\n",
    "    \"Professors are smart.\",\n",
    "    \"Sarah knows Jason and is a student of his.\",\n",
    "    \"Sarah is a student at the University of Toronto. and UofT is in Canada.\",\n",
    "]\n",
    "\n",
    "graph: KnowledgeGraph = generate_graph(text_chunks)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This tutorial shows how to generate and visualize a knowledge graph for complex topics. It also demonstrates how to extract graphic knowledge from the language model or provided text. The tutorial highlights the iterative process of building the knowledge graph by processing text in smaller chunks and updating the graph with new information.\n",
    "\n",
    "Using this approach, we can extract various things, including:\n",
    "\n",
    "1) People and their relationships in a story.\n",
    "\n",
    "```python\n",
    "class People(BaseModel):\n",
    "    id: str\n",
    "    name: str\n",
    "    description: str\n",
    "\n",
    "class Relationship(BaseModel):\n",
    "    id: str\n",
    "    source: str\n",
    "    target: str\n",
    "    label: str\n",
    "    description: str\n",
    "\n",
    "class Story(BaseModel):\n",
    "    people: List[People]\n",
    "    relationships: List[Relationship]\n",
    "```\n",
    "\n",
    "2) Task dependencies and action items from a transcript.\n",
    "\n",
    "```python\n",
    "class Task(BaseModel):\n",
    "    id: str\n",
    "    name: str\n",
    "    description: str\n",
    "\n",
    "class Participant(BaseModel):\n",
    "    id: str\n",
    "    name: str\n",
    "    description: str\n",
    "\n",
    "class Assignment(BaseModel):\n",
    "    id: str\n",
    "    source: str\n",
    "    target: str\n",
    "    label: str\n",
    "    description: str\n",
    "\n",
    "class Transcript(BaseModel):\n",
    "    tasks: List[Task]\n",
    "    participants: List[Participant]\n",
    "    assignments: List[Assignment]\n",
    "```\n",
    "\n",
    "3) Key concepts and their relationships from a research paper.\n",
    "4) Entities and their relationships from a news article.\n",
    "\n",
    "As an exercise, try to implement one of the above examples.\n",
    "\n",
    "All of them will follow an idea of iteratively extracting more and more information and accumulating it into some state."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
