{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "6d707723-cdb9-4de8-89db-4c6449d09fd3",
   "metadata": {},
   "source": [
    "# Run HistoricalLetters model\n",
    "\n",
    "This notebook shows how to run the `HistoricalLetters` model to create a `LetterLedger`. After running a model for a given number of steps, the ledger contains all send letters with information of sender, recipient, their geographical positions, the \"topic\" of the letter and the timestamp at which this letter was sent. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "1156a6b4-634d-4367-bcfe-89e8c19c99bf",
   "metadata": {},
   "outputs": [],
   "source": [
    "from scicom.historicalletters.model import HistoricalLetters\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29ea7068-9abd-421e-a5b9-939107a0dbe8",
   "metadata": {},
   "source": [
    "The model is initialized with a number of agents (`population`) and we select that agents should have heterogenious activation probabilities (`useActivation`) and an initial social network (`useSocialNetwork`). Furthermore, two ranges are defined, as percentage of the mean average geographical distance between all agents. `moveRange` controls how many potential targets are visible for an agent, while `letterRange` defines the range for potential letter receivers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "210e84d2-3622-4bbe-ae11-8801c2e3a990",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 738 ms, sys: 7.86 ms, total: 746 ms\n",
      "Wall time: 744 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "model = HistoricalLetters(\n",
    "    population=50,\n",
    "    moveRange=0.01,\n",
    "    letterRange=0.5,\n",
    "    useActivation=True,\n",
    "    useSocialNetwork=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "48f5cc24-246c-4ee4-a038-aca13d125789",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 10.8 s, sys: 32.5 ms, total: 10.8 s\n",
      "Wall time: 10.9 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "model.run(100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "af0f7ddc-a346-49d6-9f5b-825ba7f268da",
   "metadata": {},
   "outputs": [],
   "source": [
    "letterLedger = pd.DataFrame(\n",
    "    model.letterLedger,\n",
    "    columns=['sender', 'recipient', 'sender_loc', 'recipient_loc', 'topic', 'step']\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "19586016-0ef9-41c0-b440-0cf36ca6136f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(324, 6)"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letterLedger.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f21a8958-889b-47e2-8b03-62b042faa49a",
   "metadata": {},
   "source": [
    "## Considering individual agents\n",
    "\n",
    "Each agent in the model can be accessed individually. The agents keep track of their personal topic evolution in the `topicLedger`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "952418aa-b318-48f4-a948-afcbf785644b",
   "metadata": {},
   "outputs": [],
   "source": [
    "agents = model.schedule.agents"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "1d64fdc5-0aab-40d6-bef0-df0a1beb0807",
   "metadata": {},
   "outputs": [],
   "source": [
    "a1 = agents[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "ace6c1cf-fe46-43ab-b88a-c62057d56562",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(0.26939468679520084, 0.873311972869487, 0.25061833761660357),\n",
       " (0.26939468679520084, 0.873311972869487, 0.25061833761660357),\n",
       " (0.26939468679520084, 0.873311972869487, 0.25061833761660357)]"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a1.topicLedger[:3]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ad6e26e-e57c-41d4-9835-647475adf0db",
   "metadata": {},
   "source": [
    "## Visualize letter network\n",
    "\n",
    "Each sending of a letter creates an edge in the social network of the model. This network can be used to visualize the final state of the letter network. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "c7815d32-ac9e-4019-983b-bf9988b33e33",
   "metadata": {},
   "outputs": [],
   "source": [
    "import networkx as nx"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "814232ff-48bf-41dc-85f5-3a5144180507",
   "metadata": {},
   "outputs": [],
   "source": [
    "graph = model.G"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "f11aba83-cf73-4f57-8438-64b7b6452813",
   "metadata": {},
   "outputs": [],
   "source": [
    "sizes = nx.get_node_attributes(graph, 'numLettersReceived')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "0877aad4-bbc6-4b15-a875-3449ffc57423",
   "metadata": {},
   "outputs": [],
   "source": [
    "pos = nx.spring_layout(graph)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "4c33017e-d2d7-4e48-89be-4a2d4c605620",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 119720 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "nx.draw_networkx(graph, pos=pos, node_size=list(sizes.values()), with_labels=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78c95939-9ceb-44f1-8b94-bc143b8d6689",
   "metadata": {},
   "source": [
    "## Pruning\n",
    "\n",
    "A first simple approach of pruning is removing nodes with lesser numbers of received letters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "0abc32d0-b925-44c7-abea-faf83236daa5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "50"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(graph.nodes())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "6089ad51-e49d-4170-8027-335f7f84216d",
   "metadata": {},
   "outputs": [],
   "source": [
    "lesserNodes = [x for x,y in sizes.items() if y < 10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "7e40268d-db0b-455a-ac52-1520018567b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "graph2 = graph.copy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "0b3806d7-81b3-4668-b820-83a1a68b3108",
   "metadata": {},
   "outputs": [],
   "source": [
    "graph2.remove_nodes_from(lesserNodes)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "8beda086-9c26-461a-9455-ceaf4d350764",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "12"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(graph2.nodes())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "36342ad3-9a52-4244-b6fb-f81dd3800406",
   "metadata": {},
   "outputs": [],
   "source": [
    "sizes2 = nx.get_node_attributes(graph2, 'numLettersReceived')\n",
    "pos2 = nx.spring_layout(graph2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "97715955-7f4d-44fa-9f29-f143a3c53435",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 61272 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "nx.draw_networkx(graph2,pos=pos2, node_size=list(sizes2.values()), with_labels=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "897bef83-9f9a-41fa-aefc-b3e738ebd237",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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": 5
}
