{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/08_Reasoning_and_Inference.ipynb)\n",
    "\n",
    "# Reasoning and Inference\n",
    "\n",
    "## Overview\n",
    "\n",
    "Build knowledge graphs, define rules, perform forward/backward chaining, and generate explanations for AI reasoning using the **Semantica Reasoning Module**.\n",
    "\n",
    "\n",
    "**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/reasoning/)\n",
    "\n",
    "## Installation\n",
    "\n",
    "Install Semantica from PyPI:\n",
    "\n",
    "```bash\n",
    "pip install semantica\n",
    "# Or with all optional dependencies:\n",
    "pip install semantica[all]\n",
    "```\n",
    "\n",
    "## Workflow: Build KG → Define Rules → Forward/Backward Chaining → Generate Explanations\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: Ignoring invalid distribution ~gno (C:\\Users\\Mohd Kaif\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages)\n",
      "WARNING: Ignoring invalid distribution ~lotly (C:\\Users\\Mohd Kaif\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages)\n",
      "WARNING: Ignoring invalid distribution ~ython-socketio (C:\\Users\\Mohd Kaif\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages)\n",
      "WARNING: Ignoring invalid distribution ~gno (C:\\Users\\Mohd Kaif\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages)\n",
      "WARNING: Ignoring invalid distribution ~lotly (C:\\Users\\Mohd Kaif\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages)\n",
      "WARNING: Ignoring invalid distribution ~ython-socketio (C:\\Users\\Mohd Kaif\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages)\n",
      "WARNING: Ignoring invalid distribution ~gno (C:\\Users\\Mohd Kaif\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages)\n",
      "WARNING: Ignoring invalid distribution ~lotly (C:\\Users\\Mohd Kaif\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages)\n",
      "WARNING: Ignoring invalid distribution ~ython-socketio (C:\\Users\\Mohd Kaif\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages)\n"
     ]
    }
   ],
   "source": [
    "!pip install -qU semantica\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from semantica.kg import GraphBuilder\n",
    "from semantica.reasoning import Reasoner, ExplanationGenerator\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 1: Build Knowledge Graph\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style='font-family: monospace;'><h4>🧠 Semantica - 📊 Current Progress</h4><table style='width: 100%; border-collapse: collapse;'><tr><th>Status</th><th>Action</th><th>Module</th><th>Submodule</th><th>File</th><th>Time</th></tr><tr><td>✅</td><td>Semantica is building</td><td>🧠 kg</td><td>GraphBuilder</td><td>-</td><td>0.31s</td></tr><tr><td>🔄</td><td>Semantica is building</td><td>🧠 kg</td><td>EntityResolver</td><td>-</td><td>2.16s</td></tr><tr><td>✅</td><td>Semantica is deduplicating</td><td>🔄 deduplication</td><td>DuplicateDetector</td><td>-</td><td>0.02s</td></tr><tr><td>✅</td><td>Semantica is deduplicating</td><td>🔄 deduplication</td><td>SimilarityCalculator</td><td>-</td><td>0.01s</td></tr><tr><td>✅</td><td>Semantica is deduplicating</td><td>🔄 deduplication</td><td>EntityMerger</td><td>-</td><td>0.05s</td></tr><tr><td>✅</td><td>Semantica is deduplicating</td><td>🔄 deduplication</td><td>MergeStrategyManager</td><td>-</td><td>0.01s</td></tr><tr><td>✅</td><td>Semantica is resolving</td><td>⚠️ conflicts</td><td>ConflictDetector</td><td>-</td><td>0.00s</td></tr><tr><td>✅</td><td>Semantica is reasoning</td><td>🤔 reasoning</td><td>Reasoner</td><td>-</td><td>0.01s</td></tr><tr><td>✅</td><td>Semantica is reasoning</td><td>🤔 reasoning</td><td>Reasoner</td><td>-</td><td>0.00s</td></tr><tr><td>✅</td><td>Semantica is reasoning</td><td>🤔 reasoning</td><td>ExplanationGenerator</td><td>-</td><td>0.01s</td></tr></table></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "builder = GraphBuilder()\n",
    "\n",
    "entities = [\n",
    "    {\"id\": \"alice\", \"type\": \"Person\", \"name\": \"Alice\"},\n",
    "    {\"id\": \"bob\", \"type\": \"Person\", \"name\": \"Bob\"},\n",
    "    {\"id\": \"charlie\", \"type\": \"Person\", \"name\": \"Charlie\"},\n",
    "    {\"id\": \"sf\", \"type\": \"Location\", \"name\": \"San Francisco\"},\n",
    "    {\"id\": \"california\", \"type\": \"Location\", \"name\": \"California\"},\n",
    "]\n",
    "\n",
    "relationships = [\n",
    "    {\"source\": \"alice\", \"target\": \"bob\", \"type\": \"parent_of\"},\n",
    "    {\"source\": \"bob\", \"target\": \"charlie\", \"type\": \"parent_of\"},\n",
    "    {\"source\": \"sf\", \"target\": \"california\", \"type\": \"located_in\"},\n",
    "    {\"source\": \"alice\", \"target\": \"sf\", \"type\": \"lives_in\"},\n",
    "]\n",
    "\n",
    "knowledge_graph = builder.build([{\"entities\": entities, \"relationships\": relationships}])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 2: Define Rules\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize Reasoner\n",
    "reasoner = Reasoner()\n",
    "\n",
    "# Define rules using logic syntax\n",
    "rules = [\n",
    "    \"IF parent_of(?a, ?b) AND parent_of(?b, ?c) THEN grandparent_of(?a, ?c)\",\n",
    "    \"IF lives_in(?x, ?y) AND located_in(?y, ?z) THEN lives_in(?x, ?z)\"\n",
    "]\n",
    "\n",
    "for rule in rules:\n",
    "    reasoner.add_rule(rule)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 3: Forward Chaining\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Inferred 2 new facts:\n",
      " - grandparent_of(alice, charlie)\n",
      " - lives_in(alice, california)\n"
     ]
    }
   ],
   "source": [
    "# Perform forward chaining to derive new facts\n",
    "# The Reasoner can infer facts directly from the knowledge graph or a list of facts\n",
    "inferred_facts = reasoner.infer_facts(knowledge_graph)\n",
    "\n",
    "print(f\"Inferred {len(inferred_facts)} new facts:\")\n",
    "for fact in inferred_facts:\n",
    "    print(f\" - {fact}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 4: Backward Chaining\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Goal 'grandparent_of(alice, charlie)' proven successfully!\n"
     ]
    }
   ],
   "source": [
    "# Define a goal to prove\n",
    "goal = \"grandparent_of(alice, charlie)\"\n",
    "\n",
    "# Perform backward chaining\n",
    "proof = reasoner.backward_chain(goal)\n",
    "\n",
    "if proof:\n",
    "    print(f\"Goal '{goal}' proven successfully!\")\n",
    "else:\n",
    "    print(f\"Could not prove goal '{goal}'.\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 5: Generate Explanations\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Explanation for backward chaining proof:\n",
      "Given the premises: parent_of(alice, bob), parent_of(bob, charlie), we conclude: grandparent_of(alice, charlie).\n"
     ]
    }
   ],
   "source": [
    "generator = ExplanationGenerator()\n",
    "\n",
    "# If we have a proof from backward chaining, explain it\n",
    "if proof:\n",
    "    proof_explanation = generator.generate_explanation(proof)\n",
    "    print(\"Explanation for backward chaining proof:\")\n",
    "    print(proof_explanation.natural_language)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "Reasoning and inference workflow:\n",
    "- Knowledge Graph Built\n",
    "- Inference Rules Defined\n",
    "- Facts Loaded into Engine\n",
    "- Forward Chaining Performed\n",
    "- Backward Chaining Performed\n",
    "- Explanations Generated\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "### Deep Dive: Reasoning Module\n",
    "\n",
    "This section provides an in-depth guide to Semantica's reasoning capabilities. Learn rule syntax, fact formats, chaining strategies, and explanation generation with robust, reproducible examples.\n",
    "\n",
    "**What you'll practice**\n",
    "- Defining rules with variables and predicates\n",
    "- Loading facts in predicate form\n",
    "- Running forward and backward chaining\n",
    "- Generating human-readable explanations\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from semantica.kg import GraphBuilder\n",
    "from semantica.reasoning import Reasoner, ExplanationGenerator\n",
    "\n",
    "builder = GraphBuilder()\n",
    "reasoner = Reasoner()\n",
    "explainer = ExplanationGenerator()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Rule Syntax\n",
    "\n",
    "Rules use predicate logic with variables prefixed by `?`.\n",
    "\n",
    "- Example: `IF parent_of(?a, ?b) AND parent_of(?b, ?c) THEN grandparent_of(?a, ?c)`\n",
    "- Variables unify across predicates in the same rule\n",
    "- Conclusions are added as new facts when conditions match\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "entities = [\n",
    "    {\"id\": \"alice\", \"type\": \"Person\", \"name\": \"Alice\"},\n",
    "    {\"id\": \"bob\", \"type\": \"Person\", \"name\": \"Bob\"},\n",
    "    {\"id\": \"charlie\", \"type\": \"Person\", \"name\": \"Charlie\"},\n",
    "    {\"id\": \"sf\", \"type\": \"Location\", \"name\": \"San Francisco\"},\n",
    "    {\"id\": \"california\", \"type\": \"Location\", \"name\": \"California\"}\n",
    "]\n",
    "\n",
    "relationships = [\n",
    "    {\"source\": \"alice\", \"target\": \"bob\", \"type\": \"parent_of\"},\n",
    "    {\"source\": \"bob\", \"target\": \"charlie\", \"type\": \"parent_of\"},\n",
    "    {\"source\": \"sf\", \"target\": \"california\", \"type\": \"located_in\"},\n",
    "    {\"source\": \"alice\", \"target\": \"sf\", \"type\": \"lives_in\"}\n",
    "]\n",
    "\n",
    "knowledge_graph = builder.build([{\"entities\": entities, \"relationships\": relationships}])\n",
    "print(len(knowledge_graph.get(\"entities\", [])))\n",
    "print(len(knowledge_graph.get(\"relationships\", [])))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "rules = [\n",
    "    \"IF parent_of(?a, ?b) AND parent_of(?b, ?c) THEN grandparent_of(?a, ?c)\",\n",
    "    \"IF lives_in(?x, ?y) AND located_in(?y, ?z) THEN lives_in(?x, ?z)\"\n",
    "]\n",
    "for r in rules:\n",
    "    reasoner.add_rule(r)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "grandparent_of(alice, charlie)\n",
      "lives_in(alice, california)\n"
     ]
    }
   ],
   "source": [
    "for rel in relationships:\n",
    "    fact = f\"{rel['type']}({rel['source']}, {rel['target']})\"\n",
    "    reasoner.add_fact(fact)\n",
    "\n",
    "derived = reasoner.forward_chain()\n",
    "print(len(derived))\n",
    "for d in derived:\n",
    "    print(d.conclusion)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "grandparent_of(alice, charlie)\n",
      "True\n",
      "lives_in(alice, california)\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "goals = [\n",
    "    \"grandparent_of(alice, charlie)\",\n",
    "    \"lives_in(alice, california)\"\n",
    "]\n",
    "for g in goals:\n",
    "    proof = reasoner.backward_chain(g)\n",
    "    print(g)\n",
    "    print(bool(proof))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Given the premises: parent_of(alice, bob), parent_of(bob, charlie), we conclude: grandparent_of(alice, charlie) using rule 'Rule 1'.\n",
      "Given the premises: , we conclude: grandparent_of(alice, charlie).\n"
     ]
    }
   ],
   "source": [
    "if derived:\n",
    "    exp = explainer.generate_explanation(derived[0])\n",
    "    print(exp.natural_language)\n",
    "\n",
    "goal = \"grandparent_of(alice, charlie)\"\n",
    "proof = reasoner.backward_chain(goal)\n",
    "if proof:\n",
    "    pexp = explainer.generate_explanation(proof)\n",
    "    print(pexp.natural_language)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
