{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e8cfec04",
   "metadata": {},
   "source": [
    "# Demonstrative Examples"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "99b34125",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "afae3bde",
   "metadata": {},
   "source": [
    "## 1. Load sample dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "0d2960e2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "shape of alarm data: (30691, 4)\n",
      "shape of true graph: (59, 59)\n",
      "shape of causal prior matrix: (59, 59)\n"
     ]
    }
   ],
   "source": [
    "# alarm data\n",
    "alarms = pd.read_csv(r'./sample/alarm.csv')\n",
    "# causal_prior\n",
    "causal_prior= np.load(r'./sample/causal_prior.npy')\n",
    "# ground_truths, this file will not be provided in the submission stage\n",
    "true_graph = np.load(r'./sample/true_graph.npy')\n",
    "\n",
    "print(f\"shape of alarm data: {alarms.shape}\")\n",
    "print(f\"shape of true graph: {true_graph.shape}\")\n",
    "print(f\"shape of causal prior matrix: {causal_prior.shape}\")\n",
    "\n",
    "# Notes: topology.npy and rca_prior.csv are not used in this demo code."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43ade713",
   "metadata": {},
   "source": [
    "## 2.  Select the gCastle as the base algorithm library"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "102fd26b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from castle.algorithms import Notears,PC\n",
    "from castle.common.plot_dag import GraphDAG\n",
    "from castle.metrics import MetricsDAG\n",
    "from castle.common.priori_knowledge import PrioriKnowledge"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ef8993ad",
   "metadata": {},
   "source": [
    "## 3. Case Studies"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dee8f9bc",
   "metadata": {},
   "source": [
    "### 3.1 Setting 1:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21044716",
   "metadata": {},
   "source": [
    "  1. Data files: \"alarm.csv\".\n",
    "  2. Use a time sliding window to generate IID samples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0b2a4700",
   "metadata": {},
   "outputs": [],
   "source": [
    "TIME_WIN_SIZE  = 300"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "ec79d80e",
   "metadata": {},
   "outputs": [],
   "source": [
    "alarms = alarms.sort_values(by='start_timestamp')\n",
    "alarms['win_id'] = alarms['start_timestamp'].map(lambda elem:int(elem/TIME_WIN_SIZE))\n",
    "\n",
    "samples=alarms.groupby(['alarm_id','win_id'])['start_timestamp'].count().unstack('alarm_id')\n",
    "samples = samples.dropna(how='all').fillna(0)\n",
    "samples = samples.sort_index(axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "08ca1ef4",
   "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>alarm_id</th>\n",
       "      <th>0</th>\n",
       "      <th>1</th>\n",
       "      <th>2</th>\n",
       "      <th>3</th>\n",
       "      <th>4</th>\n",
       "      <th>5</th>\n",
       "      <th>6</th>\n",
       "      <th>7</th>\n",
       "      <th>8</th>\n",
       "      <th>9</th>\n",
       "      <th>...</th>\n",
       "      <th>49</th>\n",
       "      <th>50</th>\n",
       "      <th>51</th>\n",
       "      <th>52</th>\n",
       "      <th>53</th>\n",
       "      <th>54</th>\n",
       "      <th>55</th>\n",
       "      <th>56</th>\n",
       "      <th>57</th>\n",
       "      <th>58</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>win_id</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>...</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>...</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>...</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>3 rows × 59 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "alarm_id   0    1    2    3    4    5    6    7    8    9   ...   49   50  \\\n",
       "win_id                                                      ...             \n",
       "0         0.0  0.0  0.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  ...  0.0  0.0   \n",
       "1         0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  ...  0.0  1.0   \n",
       "2         1.0  0.0  0.0  0.0  0.0  0.0  1.0  1.0  1.0  0.0  ...  0.0  1.0   \n",
       "\n",
       "alarm_id   51   52   53   54   55   56   57   58  \n",
       "win_id                                            \n",
       "0         0.0  0.0  0.0  0.0  0.0  1.0  0.0  0.0  \n",
       "1         0.0  0.0  1.0  0.0  1.0  0.0  0.0  0.0  \n",
       "2         0.0  0.0  0.0  3.0  0.0  3.0  1.0  0.0  \n",
       "\n",
       "[3 rows x 59 columns]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "samples.head(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "2cba03a8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1981, 59)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "samples.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7e7c7df9",
   "metadata": {},
   "source": [
    "####  Exemplified by the NOTEARS"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "24dd01ae",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2023-08-08 20:26:27,975 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:195] - INFO: [start]: n=1981, d=59, iter_=100, h_=1e-08, rho_=1e+16\n",
      "2023-08-08 20:26:28,224 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 0] h=1.433e-01, loss=15.762, rho=1.0e+00\n",
      "2023-08-08 20:26:28,327 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 1] h=1.295e-01, loss=11.476, rho=1.0e+00\n",
      "2023-08-08 20:26:28,460 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 1] h=8.740e-02, loss=11.568, rho=1.0e+01\n",
      "2023-08-08 20:26:28,625 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 1] h=4.041e-02, loss=12.493, rho=1.0e+02\n",
      "2023-08-08 20:26:28,880 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 1] h=1.273e-02, loss=21.739, rho=1.0e+03\n",
      "2023-08-08 20:26:29,105 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 2] h=7.282e-03, loss=12.024, rho=1.0e+03\n",
      "2023-08-08 20:26:29,504 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 2] h=2.782e-03, loss=12.753, rho=1.0e+04\n",
      "2023-08-08 20:26:29,729 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 3] h=1.721e-03, loss=12.143, rho=1.0e+04\n",
      "2023-08-08 20:26:30,057 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 3] h=7.169e-04, loss=12.491, rho=1.0e+05\n",
      "2023-08-08 20:26:30,658 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 3] h=2.230e-04, loss=15.975, rho=1.0e+06\n",
      "2023-08-08 20:26:31,149 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 4] h=1.295e-04, loss=12.284, rho=1.0e+06\n",
      "2023-08-08 20:26:32,012 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 4] h=4.915e-05, loss=12.507, rho=1.0e+07\n",
      "2023-08-08 20:26:32,594 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 5] h=2.995e-05, loss=12.321, rho=1.0e+07\n",
      "2023-08-08 20:26:33,500 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 5] h=1.215e-05, loss=12.430, rho=1.0e+08\n",
      "2023-08-08 20:26:34,227 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 6] h=7.727e-06, loss=12.345, rho=1.0e+08\n",
      "2023-08-08 20:26:35,479 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 6] h=3.287e-06, loss=12.412, rho=1.0e+09\n",
      "2023-08-08 20:26:37,604 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 6] h=1.046e-06, loss=13.076, rho=1.0e+10\n",
      "2023-08-08 20:26:39,184 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 7] h=5.956e-07, loss=12.376, rho=1.0e+10\n",
      "2023-08-08 20:26:43,631 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 7] h=2.260e-07, loss=12.425, rho=1.0e+11\n",
      "2023-08-08 20:26:45,120 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 8] h=1.447e-07, loss=12.381, rho=1.0e+11\n",
      "2023-08-08 20:26:48,488 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 8] h=5.912e-08, loss=12.404, rho=1.0e+12\n",
      "2023-08-08 20:26:59,097 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 8] h=1.274e-08, loss=12.634, rho=1.0e+13\n",
      "2023-08-08 20:27:00,561 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 9] h=6.932e-09, loss=12.387, rho=1.0e+13\n",
      "2023-08-08 20:27:03,965 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:206] - INFO: [iter 9] h=2.493e-09, loss=12.395, rho=1.0e+14\n",
      "2023-08-08 20:27:03,966 - /home/zhangkeli/anaconda3/lib/python3.9/site-packages/castle/algorithms/gradient/notears/linear.py[line:222] - INFO: FINISHED\n"
     ]
    }
   ],
   "source": [
    "nt = Notears()\n",
    "nt.learn(samples)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "625f3f2e",
   "metadata": {},
   "outputs": [],
   "source": [
    "nt_estimated_graph = nt.causal_matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "8ef19a7b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 10916 characters]\n",
      "text/plain": [
       "<Figure size 576x216 with 4 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<castle.common.plot_dag.GraphDAG at 0x7f1c72de2a00>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Plot estimated graph and true graph\n",
    "GraphDAG(nt_estimated_graph, true_graph)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "3798b431",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The performance for notears: \n",
      "{'fdr': 0.087, 'tpr': 0.1429, 'fpr': 0.0013, 'shd': 126, 'nnz': 23, 'precision': 0.913, 'recall': 0.1429, 'F1': 0.2471, 'gscore': 0.1293}\n"
     ]
    }
   ],
   "source": [
    "# Evaluation \n",
    "nt_metrics = MetricsDAG(nt_estimated_graph, true_graph)\n",
    "print(f\"The performance for notears: \\n{nt_metrics.metrics}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb160091",
   "metadata": {},
   "source": [
    "### 3.2 Setting 2:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2be814fb",
   "metadata": {},
   "source": [
    "  1. Data files: \"alarm.csv\" and 'causal_prior.csv'.\n",
    "  2. Use a time sliding window to generate IID samples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "85f0fb8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# create the prior knowledge object for the PC algorithm \n",
    "prior_knowledge = PrioriKnowledge(causal_prior.shape[0])\n",
    "for i, j in zip(*np.where(causal_prior == 1)):\n",
    "    prior_knowledge.add_required_edge(i, j)\n",
    "\n",
    "for i, j in zip(*np.where(causal_prior == 0)):\n",
    "    prior_knowledge.add_forbidden_edge(i, j)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "27f4bce1",
   "metadata": {},
   "source": [
    "#### Exemplified by the PC supporting prior knowledge injection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "aca0942f",
   "metadata": {},
   "outputs": [],
   "source": [
    "pc = PC(priori_knowledge=prior_knowledge)\n",
    "pc.learn(samples)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "dc4cec1b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 11624 characters]\n",
      "text/plain": [
       "<Figure size 576x216 with 4 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<castle.common.plot_dag.GraphDAG at 0x7f1c71309e50>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pc_estimated_graph = pc.causal_matrix\n",
    "# Plot estimated graph and true graph\n",
    "GraphDAG(pc_estimated_graph, true_graph)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "1bdf6b66",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The performance for PC with Prior Knowledge: \n",
      "{'fdr': 0.3252, 'tpr': 0.7483, 'fpr': 0.0339, 'shd': 72, 'nnz': 163, 'precision': 0.6748, 'recall': 0.7483, 'F1': 0.7097, 'gscore': 0.3878}\n"
     ]
    }
   ],
   "source": [
    "# Evaluation \n",
    "pc_metrics = MetricsDAG(pc_estimated_graph, true_graph)\n",
    "print(f\"The performance for PC with Prior Knowledge: \\n{pc_metrics.metrics}\")"
   ]
  }
 ],
 "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.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
