{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "fb6837e9",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import os\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b145dee9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'22 54 1063 1067 12 18 23 59 188 307 1043 1459 1475 1489 1497 1503 40499 44125 44131 45062 44157 1462 44160 29 37 53 49 1504 1494 41143 44126 40981 41168 44091 44158 44123 44090 40922 44161 45714'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "datalist = [\n",
    "    22, 54, 1063, 1067, 12, 18, 23, 59, 188, 307, 1043, 1459, 1475, 1489, 1497, 1503, 40499, 44125,\n",
    "    44131, 45062, 44157, 1462, 44160, 29, 37, 53, 49, 1504, 1494, 41143, 44126, 40981, 41168, 44091, 44158, 44123, 44090,\n",
    "    40922, 44161, 45714]\n",
    "\" \".join(map(str, datalist))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "087a333b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# result = pd.read_csv(\"/home/SemiTab/result-summary/result.csv\", index_col=0)\n",
    "# result = result[result[\"model\"].isin([\n",
    "#     \"sslbinshuffling-lr\", \"sslbinsampling-lr\", \"sslshuffling-lr\"])].reset_index(drop=True)\n",
    "# result = result[[\"trial\", \"shots\", \"data_id\", \"model\", \"acc\"]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "7e9af2d6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# p = pd.read_csv(\"/home/SemiTab/result-summary/result-numshots.csv\", index_col=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "6a7afd3d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# result = result[~result[\"data_id\"].isin([1492, 4153])]\n",
    "# result[\"model\"] = result[\"model\"].replace(\"sslbinshuffling-lr\", \"sslbinshuffling\")\n",
    "# result[\"model\"] = result[\"model\"].replace(\"sslbinsampling-lr\", \"sslbinsampling\")\n",
    "\n",
    "# pd.concat([result, p], axis=0).to_csv(\"/home/SemiTab/result-summary/result-numshots.csv\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5b1e9d31",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "8096b653",
   "metadata": {},
   "outputs": [],
   "source": [
    "def update(model):\n",
    "    result = pd.read_csv(\"/home/SemiTab/result-summary/result-numshots.csv\", index_col=0)\n",
    "    i = len(result)\n",
    "    print(i)\n",
    "    for trial in range(10):\n",
    "        for shot in [10, 20, 30]:\n",
    "            for d in datalist:\n",
    "                if len(result[(result[\"trial\"] == trial) & (result[\"shots\"] == shot) & (result[\"model\"] == model) & (result[\"data_id\"] == d)]) > 0:\n",
    "                    pass\n",
    "                else:\n",
    "                    fname = f'/home/SemiTab/results/seed={trial}/shot={shot}/model={model}/data={d}/performance.npy'                \n",
    "                    try:\n",
    "                        perf = np.load(fname, allow_pickle=True).item()\n",
    "                        if model.startswith(\"ssl\"):\n",
    "                            result.loc[i] = [trial, shot, d, model, perf[\"Test\"][\"lr\"][0]]\n",
    "                            i += 1\n",
    "                        else:\n",
    "                            result.loc[i] = [trial, shot, d, model, perf[\"Test\"][0]]\n",
    "                            i += 1\n",
    "                    except Exception:\n",
    "                        print(trial, shot, d)\n",
    "    #                     if not (((shot >= 10) and (d in [1492, 4153]))):\n",
    "    #                         todo = True\n",
    "                        pass\n",
    "    result.to_csv(\"/home/SemiTab/result-summary/result-numshots.csv\")\n",
    "    print(result.shape)\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "1b973980",
   "metadata": {},
   "outputs": [],
   "source": [
    "def update2(model, datalist=[49], shots=[10, 20, 30], trials=range(100)):\n",
    "    result = pd.read_csv(\"/home/SemiTab/result-summary/result-numshots.csv\", index_col=0)\n",
    "    for trial in trials:\n",
    "        for shot in shots:\n",
    "            for d in datalist:\n",
    "                fname = f'/home/SemiTab/results/seed={trial}/shot={shot}/model={model}/data={d}/performance.npy'                \n",
    "                try:\n",
    "                    perf = np.load(fname, allow_pickle=True).item()\n",
    "                    if model.startswith(\"ssl\"):\n",
    "                        result.loc[\n",
    "                            (result[\"trial\"] == trial) & (result[\"shots\"] == shot) & (\n",
    "                                result[\"data_id\"] == d) & (result[\"model\"] == model), \"acc\"] = perf[\"Test\"][\"lr\"][0]\n",
    "                    else:\n",
    "                        result.loc[\n",
    "                            (result[\"trial\"] == trial) & (result[\"shots\"] == shot) & (\n",
    "                                result[\"data_id\"] == d) & (result[\"model\"] == model), \"acc\"] = perf[\"Test\"][0]\n",
    "                except Exception:\n",
    "    #                     if not (((shot >= 10) and (d in [1492, 4153]))):\n",
    "    #                         todo = True\n",
    "                    pass\n",
    "    result.to_csv(\"/home/SemiTab/result-summary/result-numshots.csv\")\n",
    "    print(result.shape)\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "fea54353",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'12 18 22 23 29 37 49 53 54 59 188 307 1043 1063 1067 1459 1462 1475 1489 1494 1497 1503 1504 40499 40922 40981 41143 41168 44090 44091 44123 44125 44126 44131 44157 44158 44160 44161 45062 45714'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\" \".join(map(str, sorted(datalist)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "77fe58e0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "95176\n",
      "(95976, 5)\n"
     ]
    }
   ],
   "source": [
    "for model in [\"sslshuffling\"]: #, \"sslbinsampling\"]:\n",
    "    result = update(model)\n",
    "result = result[~result[\"data_id\"].isin([1492, 4153])]\n",
    "result[\"model\"] = result[\"model\"].replace(\"sslbinshuffling-lr\", \"sslbinshuffling\")\n",
    "result[\"model\"] = result[\"model\"].replace(\"sslbinsampling-lr\", \"sslbinsampling\")\n",
    "\n",
    "# result[result[\"model\"] == \"sslbinsampling\"].shape\n",
    "\n",
    "# result = update2(\"sslbinshuffling\", datalist=datalist, shots=[10, 20, 30], trials=range(100))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "4b1b5674",
   "metadata": {},
   "outputs": [],
   "source": [
    "result = result[result[\"trial\"] < 10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "32da2950",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "86fc4ddd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.666132420189583\n",
      "0.6815132447427428\n"
     ]
    }
   ],
   "source": [
    "s = 30\n",
    "print(result[(result[\"shots\"] == s) & (result[\"model\"] == \"sslshuffling\")][\"acc\"].mean())\n",
    "print(result[(result[\"shots\"] == s) & (result[\"model\"] == \"sslbinshuffling\")][\"acc\"].mean())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "2aa5721a",
   "metadata": {},
   "outputs": [],
   "source": [
    "q = result.groupby([\"shots\", \"model\", \"data_id\"]).agg(\n",
    "    acc_mean=('acc', 'mean')).reset_index()\n",
    "q1 = q[(q[\"model\"] == \"mlp\") & (q[\"shots\"] == s)].sort_values(\"data_id\").reset_index(drop=True)\n",
    "q2 = q[(q[\"model\"] == \"sslbinshuffling\") & (q[\"shots\"] == s)].sort_values(\"data_id\").reset_index(drop=True)\n",
    "q1[\"diff\"] = q1[\"acc_mean\"] - q2[\"acc_mean\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "a8ddaf63",
   "metadata": {},
   "outputs": [],
   "source": [
    "# q1.sort_values(\"diff\", ascending=False)\n",
    "# q2.sort_values(\"acc_mean\")\n",
    "# q1.sort_values(\"acc_mean\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d989eba5",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 398,
   "id": "f5532c87",
   "metadata": {},
   "outputs": [],
   "source": [
    "# result = result[~result[\"model\"].str.startswith(\"sslbin\")]\n",
    "# result.to_csv(\"/home/SemiTab/result-summary/result-numshots.csv\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "248e3d5b",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "3bb1338b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,\n",
       "       60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dt = result.groupby([\"shots\", \"model\", \"trial\"]).agg(count=('acc', lambda x: x.notna().sum())).reset_index()\n",
    "# dt[(dt[\"count\"] < 40) & (dt[\"model\"] != \"sslbinsampling\")].head(5)\n",
    "dt[(dt[\"count\"] < 40) & (dt[\"model\"] == \"sslbinsampling\") & (dt[\"shots\"] == 10)][\"trial\"].values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "affdacdf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "44161 45714\n"
     ]
    }
   ],
   "source": [
    "vv = result[(result[\"model\"] == \"sslshuffling\") & (result[\"shots\"] == 10) & (\n",
    "    result[\"trial\"] == 43)][\"data_id\"]\n",
    "vv = vv.tolist() + [1492, 4153]\n",
    "print(\" \".join(map(str, [v for v in datalist if v not in vv])))\n",
    "# print(vv)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "id": "80592c94",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99\n"
     ]
    }
   ],
   "source": [
    "vv = result[(result[\"model\"] == \"sslbinsampling\") & (result[\"shots\"] == 10) & (\n",
    "    result[\"data_id\"] == 1503)][\"trial\"].values.tolist()\n",
    "print(\" \".join(map(str, [v for v in range(100) if v not in vv])))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "be449994",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "3af53f4c",
   "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>shots</th>\n",
       "      <th>model</th>\n",
       "      <th>acc_mean</th>\n",
       "      <th>acc_std</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>20</td>\n",
       "      <td>sslbinsampling</td>\n",
       "      <td>0.663222</td>\n",
       "      <td>0.169840</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>20</td>\n",
       "      <td>sslbinshuffling</td>\n",
       "      <td>0.652290</td>\n",
       "      <td>0.183541</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>20</td>\n",
       "      <td>mlp</td>\n",
       "      <td>0.650278</td>\n",
       "      <td>0.195172</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>20</td>\n",
       "      <td>lr</td>\n",
       "      <td>0.636427</td>\n",
       "      <td>0.175734</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>20</td>\n",
       "      <td>knn</td>\n",
       "      <td>0.588256</td>\n",
       "      <td>0.170446</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    shots            model  acc_mean   acc_std\n",
       "18     20   sslbinsampling  0.663222  0.169840\n",
       "19     20  sslbinshuffling  0.652290  0.183541\n",
       "17     20              mlp  0.650278  0.195172\n",
       "16     20               lr  0.636427  0.175734\n",
       "15     20              knn  0.588256  0.170446"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p[(p[\"shots\"] == 20)].sort_values(\"acc_mean\", ascending=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "id": "d011c080",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "6ade4e01",
   "metadata": {},
   "outputs": [],
   "source": [
    "q1 = result.groupby([\"shots\", \"model\", \"data_id\"]).agg(\n",
    "    acc_mean=('acc', 'mean')).reset_index()\n",
    "\n",
    "import copy\n",
    "rankdata = copy.deepcopy(q1)\n",
    "\n",
    "for shot in [1, 5, 10, 20, 30]:\n",
    "    for data in datalist:\n",
    "        q = q1[(q1[\"data_id\"] == data) & (q1[\"shots\"] == shot)]\n",
    "        q = q.reset_index(drop=True)\n",
    "    \n",
    "        q['rank'] = q[\"acc_mean\"].rank(ascending=False, method=\"min\")\n",
    "\n",
    "        for i, row in q.iterrows():\n",
    "            rankdata.loc[(rankdata[\"data_id\"] == row[\"data_id\"]) & \n",
    "                         (rankdata[\"shots\"] == shot) & \n",
    "                         (rankdata[\"acc_mean\"] == row[\"acc_mean\"]), 'rank'] = row['rank']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1e32441c",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "id": "0fdcb9ad",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([   23,    53,    54,   307,  1504, 41143, 44090, 44125, 44158,\n",
       "       44161])"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# rankdata[(rankdata[\"shots\"] == 10) & (rankdata[\"model\"] == \"sslbinshuffling\") & (rankdata[\"rank\"] > 4)][\"data_id\"].unique()\n",
    "rankdata[(rankdata[\"shots\"] == 10) & (rankdata[\"model\"] == \"mlp\") & (rankdata[\"rank\"] == 1)][\"data_id\"].unique()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "id": "230fa550",
   "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>shots</th>\n",
       "      <th>model</th>\n",
       "      <th>data_id</th>\n",
       "      <th>acc_mean</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>508</th>\n",
       "      <td>10</td>\n",
       "      <td>mlp</td>\n",
       "      <td>44090</td>\n",
       "      <td>0.727994</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>468</th>\n",
       "      <td>10</td>\n",
       "      <td>lr</td>\n",
       "      <td>44090</td>\n",
       "      <td>0.709222</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>588</th>\n",
       "      <td>10</td>\n",
       "      <td>sslbinshuffling</td>\n",
       "      <td>44090</td>\n",
       "      <td>0.687436</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>548</th>\n",
       "      <td>10</td>\n",
       "      <td>sslbinsampling</td>\n",
       "      <td>44090</td>\n",
       "      <td>0.678758</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>428</th>\n",
       "      <td>10</td>\n",
       "      <td>knn</td>\n",
       "      <td>44090</td>\n",
       "      <td>0.662663</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     shots            model  data_id  acc_mean\n",
       "508     10              mlp    44090  0.727994\n",
       "468     10               lr    44090  0.709222\n",
       "588     10  sslbinshuffling    44090  0.687436\n",
       "548     10   sslbinsampling    44090  0.678758\n",
       "428     10              knn    44090  0.662663"
      ]
     },
     "execution_count": 115,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q1[(q1[\"shots\"] == 10) & (q1[\"data_id\"] == 44090)].sort_values(\"acc_mean\", ascending=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1c95cf7b",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a0e1d3f",
   "metadata": {},
   "outputs": [],
   "source": [
    "result = pd.read_csv(\"/home/SemiTab/result-summary/result.csv\", index_col=0)\n",
    "result = result[result[\"model\"].isin([\n",
    "    \"sslbinshuffling-lr\", \"sslbinsampling-lr\", \"sslshuffling-lr\"])].reset_index(drop=True)\n",
    "result = result[[\"trial\", \"shots\", \"data_id\", \"model\", \"acc\"]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "35e27932",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 371,
   "id": "14c20256",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "c72188b5",
   "metadata": {},
   "outputs": [],
   "source": [
    "p = result[result[\"trial\"] < 10].groupby([\"shots\", \"model\"]).agg(\n",
    "    acc_mean=('acc', 'mean'), acc_std=('acc', 'std')).reset_index()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "e20dd792",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 26900 characters]\n",
      "text/plain": [
       "<Figure size 288x216 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "labels = {\"lr\": \"LR\", \"knn\": \"kNN\", \"mlp\": \"MLP\", \n",
    "          \"sslshuffling\": \"CL+Shuffling\",\n",
    "          \"sslbinshuffling\": \"Ours\", #\"CL+Range-limited Shuffling\", \n",
    "          \"sslbinsampling\": \"CL+Range-limited Sampling\"}\n",
    "\n",
    "plt.figure(figsize=(4, 3))\n",
    "plt.gca().set_axisbelow(True)\n",
    "plt.grid()\n",
    "for model in [\"lr\", \"knn\", \"mlp\", \"sslshuffling\", \"sslbinshuffling\"]: #, \"sslbinsampling\"]:\n",
    "    q = p[p[\"model\"] == model]\n",
    "    plt.plot(q[\"shots\"], q[\"acc_mean\"], label=labels[model], marker=\"o\")\n",
    "plt.legend(loc=\"lower right\")\n",
    "plt.xlabel(\"Shots\", fontsize=12)\n",
    "plt.ylabel(\"Average Accuracy\", fontsize=12)\n",
    "plt.savefig(\"figs/discussion-shots.png\", dpi=300, bbox_inches=\"tight\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "829440c8",
   "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.8.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
