{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import os\n",
    "import sumolib\n",
    "import copy\n",
    "import json\n",
    "from tqdm import tqdm\n",
    "from datetime import datetime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "m = 105\n",
    "midnight = int(datetime(2024, 1, 5, 0, 0, 0).timestamp())\n",
    "next_day = int(datetime(2024, 1, 6, 0, 0, 0).timestamp())\n",
    "fmins = range(midnight, next_day, 300)\n",
    "\n",
    "# 현재시각\n",
    "present_time = fmins[m]\n",
    "sim_start = fmins[m] - 300\n",
    "# network and dataframes\n",
    "net = sumolib.net.readNet('../Data/networks/sn.net.xml')\n",
    "inter_node = pd.read_csv('../Data/tables/inter_node.csv', index_col=0)\n",
    "plan = pd.read_csv('../Data/tables/plan.csv', index_col=0)\n",
    "match6 = pd.read_csv('../Intermediates/match6.csv', index_col=0)\n",
    "match6 = match6[['node_id', 'phase_no', 'ring_type', 'inc_edge', 'out_edge']].reset_index(drop=True)\n",
    "histid = pd.read_csv(f'../Intermediates/histid/histid_{present_time}.csv', index_col=0)\n",
    "histid = histid.reset_index(drop=True).drop(columns=['inter_no'])\n",
    "\n",
    "# helper dictionaries and lists\n",
    "inter_node_p = inter_node[inter_node.inter_type=='parent']\n",
    "inter2node = dict(zip(inter_node_p['inter_no'], inter_node_p['node_id']))\n",
    "node2inter = dict(zip(inter_node['node_id'], inter_node['inter_no']))\n",
    "pa2ch = {'i0':['u00'], 'i1':[], 'i2':['u20'], 'i3':['c30', 'u30', 'u31', 'u32'], 'i6':['u60'], 'i7':[], 'i8':[], 'i9':[]}\n",
    "node_ids = sorted(inter_node.node_id.unique())\n",
    "parent_ids = sorted(inter_node[inter_node.inter_type=='parent'].node_id.unique())\n",
    "nodes = [net.getNode(node_id) for node_id in node_ids]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def attach_children(histid, match6, parent_ids, pa2ch):\n",
    "    '''\n",
    "    자식교차로에 대한 진입·진출 엣지 정보를 붙여주는 함수\n",
    "\n",
    "    input :\n",
    "    (1) histid\n",
    "     - 각 교차로에 대한 (시작유닉스, A현시, B현시)별 현시시간, 진입·진출엣지\n",
    "     - 부모교차로(주교차로)에 대해서만 값이 지정되어 있음\n",
    "    (2) match6\n",
    "     - (현시, 링)별 진입·진출엣지\n",
    "     - 자식교차로(유턴 및 연동교차로)에 대해서도 값이 지정되어 있음\n",
    "    (3) parent_ids : 부모교차로 목록\n",
    "    (4) pa2ch : 각 부모교차로id를 부모교차로가 포함하고 있는 자식교차로들의 id들의 리스트로 대응시키는 딕셔너리\n",
    "\n",
    "    output : histids\n",
    "     - 모든(부모 및 자식) 교차로에 대한 시작유닉스 (시작유닉스, A현시, B현시)별 현시시간, 진입·진출엣지\n",
    "    '''\n",
    "    new_histids = []\n",
    "    for parent_id in parent_ids:\n",
    "        for child_id in pa2ch[parent_id]:\n",
    "            new_histid = histid.copy()[histid.node_id==parent_id]\n",
    "            new_histid[['inc_edge_A', 'out_edge_A', 'inc_edge_B', 'out_edge_B']] = np.nan\n",
    "            for i, row in new_histid.iterrows():\n",
    "                phas_A = row.phas_A\n",
    "                phas_B = row.phas_B\n",
    "                new_match = match6[match6.node_id==child_id]\n",
    "                Arow = new_match[(new_match.phase_no==phas_A) & (new_match.ring_type=='A')]\n",
    "                if ~ Arow[['inc_edge', 'out_edge']].isna().all().all():\n",
    "                    inc_edge = Arow.iloc[0].inc_edge\n",
    "                    out_edge = Arow.iloc[0].out_edge\n",
    "                    new_histid.loc[i, ['inc_edge_A', 'out_edge_A']] = [inc_edge, out_edge]\n",
    "                Brow = new_match[(new_match.phase_no==phas_B) & (new_match.ring_type=='B')]\n",
    "                if ~ Brow[['inc_edge', 'out_edge']].isna().all().all():\n",
    "                    inc_edge = Brow.iloc[0].inc_edge\n",
    "                    out_edge = Brow.iloc[0].out_edge\n",
    "                    new_histid.loc[i, ['inc_edge_B', 'out_edge_B']] = [inc_edge, out_edge]\n",
    "                new_histid.loc[i, 'node_id'] = child_id\n",
    "            new_histids.append(new_histid)\n",
    "    new_histids = pd.concat(new_histids)\n",
    "    histids = pd.concat([histid.copy(), new_histids])\n",
    "    histids = histids.sort_values(by=['start_unix', 'node_id', 'phas_A', 'phas_B']).reset_index(drop=True)\n",
    "    return histids\n",
    "histids = attach_children(histid, match6, parent_ids, pa2ch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def initialize_states(net, nodes, histids):\n",
    "    '''\n",
    "    신호 초기화\n",
    "\n",
    "    input :\n",
    "    (1) net : 네트워크\n",
    "    (2) nodes : 노드 목록\n",
    "    (3) histids : 모든 교차로에 대한 시작유닉스 (시작유닉스, A현시, B현시)별 현시시간, 진입·진출엣지\n",
    "\n",
    "    output : node2init\n",
    "     - 각 노드를 초기화된 신호로 맵핑하는 딕셔너리\n",
    "     - 초기화된 신호란, 우회전을 g로 나머지는 r로 지정한 신호를 말함.\n",
    "    '''\n",
    "    node2init = {}\n",
    "    for node in nodes:\n",
    "        node_id = node.getID()\n",
    "        conns = [(c.getJunctionIndex(), c) for c in node.getConnections()]\n",
    "        conns = [c for c in conns if c[0] >= 0]\n",
    "        conns = sorted(conns, key=lambda x: x[0])\n",
    "        state = []\n",
    "        for i, ci in conns:\n",
    "            if ci.getTLLinkIndex() < 0:\n",
    "                continue\n",
    "            are_foes = False\n",
    "            for j, cj in conns:\n",
    "                if ci.getTo() == cj.getTo():\n",
    "                    continue\n",
    "                if node.areFoes(i, j):\n",
    "                    are_foes = True\n",
    "                    break\n",
    "            state.append('r' if are_foes else 'g')\n",
    "        node2init[node_id] = state\n",
    "\n",
    "    # 어떤 연결과도 상충이 일어나지는 않지만, 신호가 부여되어 있는 경우에는 r을 부여\n",
    "    for _, row in histids.iterrows():\n",
    "        node_id = row['node_id']\n",
    "        inc_edge_A = row.inc_edge_A\n",
    "        inc_edge_B = row.inc_edge_B\n",
    "        out_edge_A = row.out_edge_A\n",
    "        out_edge_B = row.out_edge_B\n",
    "\n",
    "        if pd.isna(inc_edge_A) or pd.isna(out_edge_A):\n",
    "            pass\n",
    "        else:\n",
    "            inc_edge_A = net.getEdge(inc_edge_A)\n",
    "            out_edge_A = net.getEdge(out_edge_A)\n",
    "            for conn in inc_edge_A.getConnections(out_edge_A):\n",
    "                index = conn.getTLLinkIndex()\n",
    "                if index >= 0:\n",
    "                    node2init[node_id][index] = 'r'\n",
    "\n",
    "        if pd.isna(inc_edge_B) or pd.isna(out_edge_B):\n",
    "            pass\n",
    "        else:\n",
    "            inc_edge_B = net.getEdge(inc_edge_B)\n",
    "            out_edge_B = net.getEdge(out_edge_B)\n",
    "            for conn in inc_edge_B.getConnections(out_edge_B):\n",
    "                index = conn.getTLLinkIndex()\n",
    "                if index >= 0:\n",
    "                    node2init[node_id][index] = 'r'\n",
    "    return node2init\n",
    "node2init = initialize_states(net, nodes, histids)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def assign_signals(histids, node2init, net):\n",
    "    '''\n",
    "    진입·진출엣지를 신호문자열로 배정\n",
    "\n",
    "    input :\n",
    "    (1) histids : 모든 교차로에 대한 (시작유닉스, A현시, B현시)별 현시시간, 진입·진출엣지\n",
    "    (2) node2init : 각 노드를 초기화된 신호로 맵핑하는 딕셔너리\n",
    "    (3) net : 네트워크\n",
    "\n",
    "    output : sigtable\n",
    "     - 모든 교차로에 대한 (시작유닉스, A현시, B현시)별 현시시간, 신호문자열\n",
    "     - 황색 및 적색신호는 아직 반영되지 않았음.\n",
    "    '''\n",
    "    sigtable = histids.copy()\n",
    "    sigtable['init_state'] = sigtable['node_id'].map(node2init)\n",
    "    sigtable['state'] = sigtable['init_state'].map(lambda x:''.join(x))\n",
    "    for i, row in sigtable.iterrows():\n",
    "        node_id = row.node_id\n",
    "        inc_edge_A = row.inc_edge_A\n",
    "        inc_edge_B = row.inc_edge_B\n",
    "        out_edge_A = row.out_edge_A\n",
    "        out_edge_B = row.out_edge_B\n",
    "        state = copy.deepcopy(node2init)[node_id]\n",
    "        if pd.isna(inc_edge_A) or pd.isna(out_edge_A):\n",
    "            pass\n",
    "        else:\n",
    "            inc_edge_A = net.getEdge(inc_edge_A)\n",
    "            out_edge_A = net.getEdge(out_edge_A)\n",
    "            for conn in inc_edge_A.getConnections(out_edge_A):\n",
    "                index = conn.getTLLinkIndex()\n",
    "                if index >= 0:\n",
    "                    state[index] = 'G'\n",
    "            sigtable.at[i, 'state'] = ''.join(state)\n",
    "\n",
    "        if pd.isna(inc_edge_B) or pd.isna(out_edge_B):\n",
    "            pass\n",
    "        else:\n",
    "            inc_edge_B = net.getEdge(inc_edge_B)\n",
    "            out_edge_B = net.getEdge(out_edge_B)\n",
    "            for conn in inc_edge_B.getConnections(out_edge_B):\n",
    "                index = conn.getTLLinkIndex()\n",
    "                if index >= 0:\n",
    "                    state[index] = 'G'\n",
    "            sigtable.at[i, 'state'] = ''.join(state)\n",
    "    sigtable = sigtable.dropna(subset='state')\n",
    "    sigtable = sigtable.reset_index(drop=True)\n",
    "    sigtable['phase_sumo'] = sigtable.groupby(['node_id', 'start_unix']).cumcount()\n",
    "    sigtable = sigtable[['node_id', 'start_unix', 'phase_sumo', 'duration', 'state']]\n",
    "    sigtable = sigtable.sort_values(by=['start_unix', 'node_id'])\n",
    "    sigtable['start_dt'] = sigtable['start_unix'].apply(lambda x:datetime.fromtimestamp(x))\n",
    "    return sigtable\n",
    "sigtable = assign_signals(histids, node2init, net)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 21736 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "k = 0\n",
    "for node_id, group in sigtable.groupby('node_id'):\n",
    "    k += 1\n",
    "    plt.plot(group.start_unix.unique(), [k] * len(group.start_unix.unique()), marker='o')\n",
    "    plt.axvline(present_time - 300, c='r', linewidth=.5)\n",
    "    plt.axvline(present_time, c='r', linewidth=.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'c30': 4,\n",
       " 'i0': 3,\n",
       " 'i1': 4,\n",
       " 'i2': 4,\n",
       " 'i3': 4,\n",
       " 'i6': 4,\n",
       " 'i7': 4,\n",
       " 'i8': 4,\n",
       " 'i9': 4,\n",
       " 'u00': 3,\n",
       " 'u20': 4,\n",
       " 'u30': 4,\n",
       " 'u31': 4,\n",
       " 'u32': 4,\n",
       " 'u60': 4}"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# node2num_cycles : A dictionary that maps a node_id to the number of cycles\n",
    "def get_node2num_cycles(plan, node_ids):\n",
    "    Aplan = plan.copy()[['inter_no'] + [f'dura_A{j}' for j in range(1,9)] + ['cycle']]\n",
    "    grouped = Aplan.groupby('inter_no')\n",
    "    df = grouped.agg({'cycle': 'min'}).reset_index()\n",
    "    df = df.rename(columns={'cycle': 'min_cycle'})\n",
    "    df['num_cycle'] = 300 // df['min_cycle'] + 2\n",
    "    inter2num_cycles = dict(zip(df['inter_no'], df['num_cycle']))\n",
    "    node2numcycles = {node_id : inter2num_cycles[node2inter[node_id]] for node_id in node_ids}\n",
    "    with open('../Intermediates/node2numcycles.json', 'w') as file:\n",
    "        json.dump(node2numcycles, file, indent=4)\n",
    "    return node2numcycles\n",
    "node2num_cycles = get_node2num_cycles(plan, node_ids)\n",
    "node2num_cycles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def set_timepoints(sigtable, node2num_cycles, present_time):\n",
    "    offsets = {}\n",
    "    Sigtable = []\n",
    "    sim_start = present_time - 300\n",
    "    for node_id, group in sigtable.groupby('node_id'):\n",
    "        lsbs = group[group['start_unix'] < sim_start]['start_unix'].max() # the last start_unix before sim_start\n",
    "        offsets[node_id] = lsbs - sim_start\n",
    "        group = group[group.start_unix >= lsbs]\n",
    "        start_unixes = np.array(group.start_unix)\n",
    "        start_unixes = np.sort(np.unique(start_unixes))[:node2num_cycles[node_id]]\n",
    "        group = group[group.start_unix.isin(start_unixes)]\n",
    "        Sigtable.append(group)\n",
    "    Sigtable = pd.concat(Sigtable)\n",
    "    return Sigtable, offsets\n",
    "Sigtable, offsets = set_timepoints(sigtable, node2num_cycles, present_time)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'c30': 4,\n",
       " 'i0': 3,\n",
       " 'i1': 4,\n",
       " 'i2': 4,\n",
       " 'i3': 4,\n",
       " 'i6': 4,\n",
       " 'i7': 4,\n",
       " 'i8': 4,\n",
       " 'i9': 4,\n",
       " 'u00': 3,\n",
       " 'u20': 4,\n",
       " 'u30': 4,\n",
       " 'u31': 4,\n",
       " 'u32': 4,\n",
       " 'u60': 4}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "node2num_cycles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 c30 4\n",
      "2 i0 3\n",
      "3 i1 4\n",
      "4 i2 4\n",
      "5 i3 4\n",
      "6 i6 4\n",
      "7 i7 4\n",
      "8 i8 4\n",
      "9 i9 4\n",
      "10 u00 3\n",
      "11 u20 4\n",
      "12 u30 4\n",
      "13 u31 4\n",
      "14 u32 4\n",
      "15 u60 4\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 21140 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "k = 0\n",
    "for node_id, group in Sigtable.groupby('node_id'):\n",
    "    k += 1\n",
    "    print(k, node_id, node2num_cycles[node_id])\n",
    "    plt.plot(group.start_unix.unique(), [k] * len(group.start_unix.unique()), marker='o')\n",
    "    plt.axvline(present_time - 300, c='r', linewidth=.5)\n",
    "    plt.axvline(present_time, c='r', linewidth=.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>node_id</th>\n",
       "      <th>start_unix</th>\n",
       "      <th>phase_sumo</th>\n",
       "      <th>duration</th>\n",
       "      <th>state</th>\n",
       "      <th>start_dt</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>i7</td>\n",
       "      <td>1704411320</td>\n",
       "      <td>0</td>\n",
       "      <td>44</td>\n",
       "      <td>GGrggGG</td>\n",
       "      <td>2024-01-05 08:35:20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>i7</td>\n",
       "      <td>1704411320</td>\n",
       "      <td>1</td>\n",
       "      <td>44</td>\n",
       "      <td>rrrggrr</td>\n",
       "      <td>2024-01-05 08:35:20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>i7</td>\n",
       "      <td>1704411320</td>\n",
       "      <td>2</td>\n",
       "      <td>26</td>\n",
       "      <td>GGrggGG</td>\n",
       "      <td>2024-01-05 08:35:20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>i7</td>\n",
       "      <td>1704411320</td>\n",
       "      <td>3</td>\n",
       "      <td>26</td>\n",
       "      <td>rrrggrr</td>\n",
       "      <td>2024-01-05 08:35:20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>c30</td>\n",
       "      <td>1704411350</td>\n",
       "      <td>0</td>\n",
       "      <td>38</td>\n",
       "      <td>rrrrrr</td>\n",
       "      <td>2024-01-05 08:35:50</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>410</th>\n",
       "      <td>u20</td>\n",
       "      <td>1704412330</td>\n",
       "      <td>1</td>\n",
       "      <td>13</td>\n",
       "      <td>ggrggg</td>\n",
       "      <td>2024-01-05 08:52:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>411</th>\n",
       "      <td>u20</td>\n",
       "      <td>1704412330</td>\n",
       "      <td>2</td>\n",
       "      <td>38</td>\n",
       "      <td>ggGggg</td>\n",
       "      <td>2024-01-05 08:52:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>412</th>\n",
       "      <td>u20</td>\n",
       "      <td>1704412330</td>\n",
       "      <td>3</td>\n",
       "      <td>18</td>\n",
       "      <td>ggrggg</td>\n",
       "      <td>2024-01-05 08:52:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>413</th>\n",
       "      <td>i9</td>\n",
       "      <td>1704412340</td>\n",
       "      <td>0</td>\n",
       "      <td>26</td>\n",
       "      <td>GGGG</td>\n",
       "      <td>2024-01-05 08:52:20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>414</th>\n",
       "      <td>i9</td>\n",
       "      <td>1704412340</td>\n",
       "      <td>1</td>\n",
       "      <td>64</td>\n",
       "      <td>rrrr</td>\n",
       "      <td>2024-01-05 08:52:20</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>415 rows × 6 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "    node_id  start_unix  phase_sumo  duration    state            start_dt\n",
       "0        i7  1704411320           0        44  GGrggGG 2024-01-05 08:35:20\n",
       "1        i7  1704411320           1        44  rrrggrr 2024-01-05 08:35:20\n",
       "2        i7  1704411320           2        26  GGrggGG 2024-01-05 08:35:20\n",
       "3        i7  1704411320           3        26  rrrggrr 2024-01-05 08:35:20\n",
       "4       c30  1704411350           0        38   rrrrrr 2024-01-05 08:35:50\n",
       "..      ...         ...         ...       ...      ...                 ...\n",
       "410     u20  1704412330           1        13   ggrggg 2024-01-05 08:52:10\n",
       "411     u20  1704412330           2        38   ggGggg 2024-01-05 08:52:10\n",
       "412     u20  1704412330           3        18   ggrggg 2024-01-05 08:52:10\n",
       "413      i9  1704412340           0        26     GGGG 2024-01-05 08:52:20\n",
       "414      i9  1704412340           1        64     rrrr 2024-01-05 08:52:20\n",
       "\n",
       "[415 rows x 6 columns]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>node_id</th>\n",
       "      <th>start_unix</th>\n",
       "      <th>phase_sumo</th>\n",
       "      <th>duration</th>\n",
       "      <th>state</th>\n",
       "      <th>start_dt</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>66</th>\n",
       "      <td>c30</td>\n",
       "      <td>1704411509</td>\n",
       "      <td>0</td>\n",
       "      <td>38</td>\n",
       "      <td>rrrrrr</td>\n",
       "      <td>2024-01-05 08:38:29</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>67</th>\n",
       "      <td>c30</td>\n",
       "      <td>1704411509</td>\n",
       "      <td>1</td>\n",
       "      <td>39</td>\n",
       "      <td>GGGGGG</td>\n",
       "      <td>2024-01-05 08:38:29</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>68</th>\n",
       "      <td>c30</td>\n",
       "      <td>1704411509</td>\n",
       "      <td>2</td>\n",
       "      <td>41</td>\n",
       "      <td>GGGGGG</td>\n",
       "      <td>2024-01-05 08:38:29</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>69</th>\n",
       "      <td>c30</td>\n",
       "      <td>1704411509</td>\n",
       "      <td>3</td>\n",
       "      <td>21</td>\n",
       "      <td>GGGGGG</td>\n",
       "      <td>2024-01-05 08:38:29</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>128</th>\n",
       "      <td>c30</td>\n",
       "      <td>1704411670</td>\n",
       "      <td>0</td>\n",
       "      <td>38</td>\n",
       "      <td>rrrrrr</td>\n",
       "      <td>2024-01-05 08:41:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>247</th>\n",
       "      <td>u60</td>\n",
       "      <td>1704411970</td>\n",
       "      <td>0</td>\n",
       "      <td>24</td>\n",
       "      <td>ggggggggr</td>\n",
       "      <td>2024-01-05 08:46:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>248</th>\n",
       "      <td>u60</td>\n",
       "      <td>1704411970</td>\n",
       "      <td>1</td>\n",
       "      <td>19</td>\n",
       "      <td>ggggggggr</td>\n",
       "      <td>2024-01-05 08:46:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>249</th>\n",
       "      <td>u60</td>\n",
       "      <td>1704411970</td>\n",
       "      <td>2</td>\n",
       "      <td>39</td>\n",
       "      <td>ggggggggG</td>\n",
       "      <td>2024-01-05 08:46:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>250</th>\n",
       "      <td>u60</td>\n",
       "      <td>1704411970</td>\n",
       "      <td>3</td>\n",
       "      <td>65</td>\n",
       "      <td>ggggggggr</td>\n",
       "      <td>2024-01-05 08:46:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>251</th>\n",
       "      <td>u60</td>\n",
       "      <td>1704411970</td>\n",
       "      <td>4</td>\n",
       "      <td>23</td>\n",
       "      <td>ggggggggr</td>\n",
       "      <td>2024-01-05 08:46:10</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>238 rows × 6 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "    node_id  start_unix  phase_sumo  duration      state            start_dt\n",
       "66      c30  1704411509           0        38     rrrrrr 2024-01-05 08:38:29\n",
       "67      c30  1704411509           1        39     GGGGGG 2024-01-05 08:38:29\n",
       "68      c30  1704411509           2        41     GGGGGG 2024-01-05 08:38:29\n",
       "69      c30  1704411509           3        21     GGGGGG 2024-01-05 08:38:29\n",
       "128     c30  1704411670           0        38     rrrrrr 2024-01-05 08:41:10\n",
       "..      ...         ...         ...       ...        ...                 ...\n",
       "247     u60  1704411970           0        24  ggggggggr 2024-01-05 08:46:10\n",
       "248     u60  1704411970           1        19  ggggggggr 2024-01-05 08:46:10\n",
       "249     u60  1704411970           2        39  ggggggggG 2024-01-05 08:46:10\n",
       "250     u60  1704411970           3        65  ggggggggr 2024-01-05 08:46:10\n",
       "251     u60  1704411970           4        23  ggggggggr 2024-01-05 08:46:10\n",
       "\n",
       "[238 rows x 6 columns]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "display(sigtable)\n",
    "display(Sigtable)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "def assign_red_yellow(Sigtable):\n",
    "    '''\n",
    "    적색, 황색신호를 반영한 신호문자열 배정\n",
    "\n",
    "    input : Sigtable\n",
    "    - 모든 교차로에 대한 (시작유닉스, 세부현시번호)별 현시시간, 신호문자열, 진입·진출엣지\n",
    "    * 세부현시란 오버랩을 반영한 현시번호를 뜻함.\n",
    "\n",
    "    output : SIGTABLE\n",
    "    - 모든 교차로에 대한 (시작유닉스, 녹황적세부현시번호)별 현시시간, (황·적색신호가 포함된) 신호문자열\n",
    "    * 녹황적세부현시번호란 세부현시번호에 r, g, y 옵션까지 포함된 현시번호를 뜻함.\n",
    "    '''\n",
    "    SIGTABLE = []\n",
    "    for node_id, group in Sigtable.groupby('node_id'):\n",
    "        new_rows_list = []\n",
    "        for i in range(1, len(group)):\n",
    "            prev_row = group.iloc[i-1:i].copy()\n",
    "            next_row = group.iloc[i:i+1].copy()\n",
    "            new_rows = pd.concat([prev_row, prev_row, next_row]).reset_index(drop=True)\n",
    "            new_rows.loc[0, 'phase_sumo'] = str(prev_row.phase_sumo.iloc[0]) + '_g'\n",
    "            new_rows.loc[0, 'duration'] = new_rows.loc[0, 'duration'] - 5\n",
    "            new_rows.loc[1, 'phase_sumo'] = str(prev_row.phase_sumo.iloc[0]) + '_y'\n",
    "            new_rows.loc[1, 'duration'] = 4\n",
    "            yellow_state = ''\n",
    "            red_state = ''\n",
    "            for a, b in zip(prev_row.state.iloc[0], next_row.state.iloc[0]):\n",
    "                if a == 'G' and b == 'r':\n",
    "                    yellow_state += 'y'\n",
    "                    red_state += 'r'\n",
    "                else:\n",
    "                    yellow_state += a\n",
    "                    red_state += a\n",
    "            new_rows.loc[2, 'phase_sumo'] = str(next_row.phase_sumo.iloc[0]) + '__r'\n",
    "            new_rows.loc[2, 'duration'] = 1\n",
    "            new_rows.loc[1, 'state'] = yellow_state\n",
    "            new_rows.loc[2, 'state'] = red_state\n",
    "            new_rows_list.append(new_rows)\n",
    "        next_row['phase_sumo'] = str(next_row.phase_sumo.iloc[0]) + '_g'\n",
    "        next_row['duration'] -= 5\n",
    "        # next_row.loc['duration'] -= 5\n",
    "        new_rows_list.append(next_row)\n",
    "        new_rows = pd.concat(new_rows_list)\n",
    "        SIGTABLE.append(new_rows)\n",
    "    SIGTABLE = pd.concat(SIGTABLE).sort_values(by=['node_id', 'start_unix', 'phase_sumo']).reset_index(drop=True)\n",
    "    return SIGTABLE\n",
    "SIGTABLE = assign_red_yellow(Sigtable)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1577804400\n",
      "2145884400\n",
      "4021\n",
      "4021\n"
     ]
    }
   ],
   "source": [
    "max_unix, min_unix = int(datetime(2020, 1, 1).timestamp()), int(datetime(2038, 1, 1).timestamp())\n",
    "print(max_unix)\n",
    "print(min_unix)\n",
    "history = pd.read_csv('../Data/tables/history.csv', index_col=0)\n",
    "K = 0\n",
    "for _, row in history.iterrows():\n",
    "    unixbool = min_unix <= row['end_unix'] <= max_unix\n",
    "    print(min_unix, row['end_unix'], max_unix)\n",
    "    if not unixbool:\n",
    "        K += 1\n",
    "print(K)\n",
    "print(len(history))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>node_id</th>\n",
       "      <th>start_unix</th>\n",
       "      <th>phase_sumo</th>\n",
       "      <th>duration</th>\n",
       "      <th>state</th>\n",
       "      <th>start_dt</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>100</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411740</td>\n",
       "      <td>1__r</td>\n",
       "      <td>1</td>\n",
       "      <td>grrGGGrgrr</td>\n",
       "      <td>2024-01-05 08:42:20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>101</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411740</td>\n",
       "      <td>1_g</td>\n",
       "      <td>88</td>\n",
       "      <td>grrGGGGgrr</td>\n",
       "      <td>2024-01-05 08:42:20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>102</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411740</td>\n",
       "      <td>1_y</td>\n",
       "      <td>4</td>\n",
       "      <td>grryyyygrr</td>\n",
       "      <td>2024-01-05 08:42:20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>103</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411740</td>\n",
       "      <td>2__r</td>\n",
       "      <td>1</td>\n",
       "      <td>grrrrrrgrr</td>\n",
       "      <td>2024-01-05 08:42:20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>104</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411740</td>\n",
       "      <td>2_g</td>\n",
       "      <td>35</td>\n",
       "      <td>grrrrrrgGG</td>\n",
       "      <td>2024-01-05 08:42:20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>105</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411740</td>\n",
       "      <td>2_y</td>\n",
       "      <td>4</td>\n",
       "      <td>grrrrrrgyy</td>\n",
       "      <td>2024-01-05 08:42:20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>106</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411910</td>\n",
       "      <td>0__r</td>\n",
       "      <td>1</td>\n",
       "      <td>grrrrrrgrr</td>\n",
       "      <td>2024-01-05 08:45:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>107</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411910</td>\n",
       "      <td>0_g</td>\n",
       "      <td>32</td>\n",
       "      <td>gGGGGGrgrr</td>\n",
       "      <td>2024-01-05 08:45:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>108</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411910</td>\n",
       "      <td>0_y</td>\n",
       "      <td>4</td>\n",
       "      <td>gyyGGGrgrr</td>\n",
       "      <td>2024-01-05 08:45:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>109</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411910</td>\n",
       "      <td>1__r</td>\n",
       "      <td>1</td>\n",
       "      <td>grrGGGrgrr</td>\n",
       "      <td>2024-01-05 08:45:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>110</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411910</td>\n",
       "      <td>1_g</td>\n",
       "      <td>88</td>\n",
       "      <td>grrGGGGgrr</td>\n",
       "      <td>2024-01-05 08:45:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>111</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411910</td>\n",
       "      <td>1_y</td>\n",
       "      <td>4</td>\n",
       "      <td>grryyyygrr</td>\n",
       "      <td>2024-01-05 08:45:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>112</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411910</td>\n",
       "      <td>2__r</td>\n",
       "      <td>1</td>\n",
       "      <td>grrrrrrgrr</td>\n",
       "      <td>2024-01-05 08:45:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>113</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411910</td>\n",
       "      <td>2_g</td>\n",
       "      <td>35</td>\n",
       "      <td>grrrrrrgGG</td>\n",
       "      <td>2024-01-05 08:45:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>114</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704411910</td>\n",
       "      <td>2_y</td>\n",
       "      <td>4</td>\n",
       "      <td>grrrrrrgyy</td>\n",
       "      <td>2024-01-05 08:45:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>115</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704412080</td>\n",
       "      <td>0__r</td>\n",
       "      <td>1</td>\n",
       "      <td>grrrrrrgrr</td>\n",
       "      <td>2024-01-05 08:48:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>116</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704412080</td>\n",
       "      <td>0_g</td>\n",
       "      <td>32</td>\n",
       "      <td>gGGGGGrgrr</td>\n",
       "      <td>2024-01-05 08:48:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>117</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704412080</td>\n",
       "      <td>0_y</td>\n",
       "      <td>4</td>\n",
       "      <td>gyyGGGrgrr</td>\n",
       "      <td>2024-01-05 08:48:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>118</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704412080</td>\n",
       "      <td>1__r</td>\n",
       "      <td>1</td>\n",
       "      <td>grrGGGrgrr</td>\n",
       "      <td>2024-01-05 08:48:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>119</th>\n",
       "      <td>i1</td>\n",
       "      <td>1704412080</td>\n",
       "      <td>1_g</td>\n",
       "      <td>88</td>\n",
       "      <td>grrGGGGgrr</td>\n",
       "      <td>2024-01-05 08:48:00</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    node_id  start_unix phase_sumo  duration       state            start_dt\n",
       "100      i1  1704411740       1__r         1  grrGGGrgrr 2024-01-05 08:42:20\n",
       "101      i1  1704411740        1_g        88  grrGGGGgrr 2024-01-05 08:42:20\n",
       "102      i1  1704411740        1_y         4  grryyyygrr 2024-01-05 08:42:20\n",
       "103      i1  1704411740       2__r         1  grrrrrrgrr 2024-01-05 08:42:20\n",
       "104      i1  1704411740        2_g        35  grrrrrrgGG 2024-01-05 08:42:20\n",
       "105      i1  1704411740        2_y         4  grrrrrrgyy 2024-01-05 08:42:20\n",
       "106      i1  1704411910       0__r         1  grrrrrrgrr 2024-01-05 08:45:10\n",
       "107      i1  1704411910        0_g        32  gGGGGGrgrr 2024-01-05 08:45:10\n",
       "108      i1  1704411910        0_y         4  gyyGGGrgrr 2024-01-05 08:45:10\n",
       "109      i1  1704411910       1__r         1  grrGGGrgrr 2024-01-05 08:45:10\n",
       "110      i1  1704411910        1_g        88  grrGGGGgrr 2024-01-05 08:45:10\n",
       "111      i1  1704411910        1_y         4  grryyyygrr 2024-01-05 08:45:10\n",
       "112      i1  1704411910       2__r         1  grrrrrrgrr 2024-01-05 08:45:10\n",
       "113      i1  1704411910        2_g        35  grrrrrrgGG 2024-01-05 08:45:10\n",
       "114      i1  1704411910        2_y         4  grrrrrrgyy 2024-01-05 08:45:10\n",
       "115      i1  1704412080       0__r         1  grrrrrrgrr 2024-01-05 08:48:00\n",
       "116      i1  1704412080        0_g        32  gGGGGGrgrr 2024-01-05 08:48:00\n",
       "117      i1  1704412080        0_y         4  gyyGGGrgrr 2024-01-05 08:48:00\n",
       "118      i1  1704412080       1__r         1  grrGGGrgrr 2024-01-05 08:48:00\n",
       "119      i1  1704412080        1_g        88  grrGGGGgrr 2024-01-05 08:48:00"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "SIGTABLE[100:120]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_tl_file(SIGTABLE, offsets, present_time):\n",
    "    strings = ['<additional>\\n']\n",
    "    for node_id, group in SIGTABLE.groupby('node_id'):\n",
    "        strings.append(f'    <tlLogic id=\"{node_id}\" type=\"static\" programID=\"{node_id}_prog\" offset=\"{offsets[node_id]}\">\\n')\n",
    "        for i, row in group.iterrows():\n",
    "            duration = row.duration\n",
    "            state = row.state\n",
    "            strings.append(f'      <phase duration=\"{duration}\" state=\"{state}\"/>\\n')\n",
    "        strings.append('    </tlLogic>\\n')\n",
    "    strings.append('</additional>')\n",
    "    strings = ''.join(strings)\n",
    "    # 저장\n",
    "    path_output = f'../Results/sn_{present_time}.add.xml'\n",
    "    with open(path_output, 'w') as f:\n",
    "        f.write(strings)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_signals(m):\n",
    "    midnight = int(datetime(2024, 1, 5, 0, 0, 0).timestamp())\n",
    "    next_day = int(datetime(2024, 1, 6, 0, 0, 0).timestamp())\n",
    "    fmins = range(midnight, next_day, 300)\n",
    "\n",
    "    # 현재시각\n",
    "    present_time = fmins[m]\n",
    "    sim_start = fmins[m] - 300\n",
    "    \n",
    "    # network and dataframes\n",
    "    net = sumolib.net.readNet('../Data/networks/sn.net.xml')\n",
    "    inter_node = pd.read_csv('../data/tables/inter_node.csv', index_col=0)\n",
    "    plan = pd.read_csv('../Data/tables/plan.csv', index_col=0)\n",
    "    match6 = pd.read_csv('../Intermediates/match6.csv', index_col=0)\n",
    "    match6 = match6[['node_id', 'phase_no', 'ring_type', 'inc_edge', 'out_edge']].reset_index(drop=True)\n",
    "    histid = pd.read_csv(f'../Intermediates/histid/histid_{present_time}.csv', index_col=0)\n",
    "    histid = histid.reset_index(drop=True).drop(columns=['inter_no'])\n",
    "    \n",
    "    # helper dictionaries and lists\n",
    "    inter_node_p = inter_node[inter_node.inter_type=='parent']\n",
    "    inter2node = dict(zip(inter_node_p['inter_no'], inter_node_p['node_id']))\n",
    "    node2inter = dict(zip(inter_node['node_id'], inter_node['inter_no']))\n",
    "    pa2ch = {'i0':['u00'], 'i1':[], 'i2':['u20'], 'i3':['c30', 'u30', 'u31', 'u32'], 'i6':['u60'], 'i7':[], 'i8':[], 'i9':[]}\n",
    "    node_ids = sorted(inter_node.node_id.unique())\n",
    "    parent_ids = sorted(inter_node[inter_node.inter_type=='parent'].node_id.unique())\n",
    "    nodes = [net.getNode(node_id) for node_id in node_ids]\n",
    "\n",
    "    # histids\n",
    "    histids = attach_children(histid, match6, parent_ids, pa2ch)\n",
    "\n",
    "    # node2init\n",
    "    node2init = initialize_states(net, nodes, histids)\n",
    "\n",
    "    # sigtable\n",
    "    sigtable = assign_signals(histids, node2init, net)\n",
    "\n",
    "    with open('../Intermediates/node2numcycles.json', 'r') as file:\n",
    "        node2numcycles = json.load(file)\n",
    "\n",
    "    # Sigtable\n",
    "    Sigtable, offsets = set_timepoints(sigtable, node2num_cycles, present_time)\n",
    "\n",
    "    # SIGTABLE\n",
    "    SIGTABLE = assign_red_yellow(Sigtable)\n",
    "\n",
    "    make_tl_file(SIGTABLE, offsets, present_time)\n",
    "    print(f'A signal file (add.xml) has been created for the timeslot between {datetime.fromtimestamp(sim_start)} and {datetime.fromtimestamp(present_time)} ({sim_start} ~ {present_time})')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A signal file (add.xml) has been created for the timeslot between 2024-01-05 08:40:00 and 2024-01-05 08:45:00 (1704411600 ~ 1704411900)\n",
      "A signal file (add.xml) has been created for the timeslot between 2024-01-05 08:45:00 and 2024-01-05 08:50:00 (1704411900 ~ 1704412200)\n"
     ]
    }
   ],
   "source": [
    "generate_signals(105)\n",
    "generate_signals(106)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "rts",
   "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.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
