{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "fc622bc9",
   "metadata": {},
   "source": [
    "# Benchmark Summary Notebook\n",
    "\n",
    "Summarise solver performance across multiple benchmark scenarios."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "abdcbd8e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-11-14T10:35:06.106958Z",
     "iopub.status.busy": "2025-11-14T10:35:06.106527Z",
     "iopub.status.idle": "2025-11-14T10:35:06.488380Z",
     "shell.execute_reply": "2025-11-14T10:35:06.487739Z"
    }
   },
   "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>scenario</th>\n",
       "      <th>scenario_path</th>\n",
       "      <th>solver</th>\n",
       "      <th>objective</th>\n",
       "      <th>runtime_s</th>\n",
       "      <th>assignments</th>\n",
       "      <th>kpi_total_production</th>\n",
       "      <th>kpi_completed_blocks</th>\n",
       "      <th>kpi_mobilisation_cost</th>\n",
       "      <th>kpi_mobilisation_cost_by_machine</th>\n",
       "      <th>...</th>\n",
       "      <th>scenario_key</th>\n",
       "      <th>objective_vs_mip_gap</th>\n",
       "      <th>objective_vs_mip_ratio</th>\n",
       "      <th>solver_category</th>\n",
       "      <th>best_heuristic_solver</th>\n",
       "      <th>best_heuristic_objective</th>\n",
       "      <th>best_heuristic_runtime_s</th>\n",
       "      <th>objective_gap_vs_best_heuristic</th>\n",
       "      <th>runtime_ratio_vs_best_heuristic</th>\n",
       "      <th>kpi_utilisation_ratio_by_role</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>user-1</td>\n",
       "      <td>examples/tiny7/scenario.yaml</td>\n",
       "      <td>sa</td>\n",
       "      <td>13.000</td>\n",
       "      <td>0.020893</td>\n",
       "      <td>16</td>\n",
       "      <td>45.500</td>\n",
       "      <td>1.0</td>\n",
       "      <td>65.0</td>\n",
       "      <td>{\"H2\": 65.0}</td>\n",
       "      <td>...</td>\n",
       "      <td>user-1</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>heuristic</td>\n",
       "      <td>sa</td>\n",
       "      <td>13.000</td>\n",
       "      <td>0.020893</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>user-1</td>\n",
       "      <td>examples/synthetic/small/scenario.yaml</td>\n",
       "      <td>sa</td>\n",
       "      <td>31.492</td>\n",
       "      <td>0.011216</td>\n",
       "      <td>3</td>\n",
       "      <td>31.492</td>\n",
       "      <td>3.0</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>...</td>\n",
       "      <td>user-1</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>heuristic</td>\n",
       "      <td>sa</td>\n",
       "      <td>31.492</td>\n",
       "      <td>0.011216</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>{\"forwarder\": 1.0, \"harvester\": 1.0}</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>user-1</td>\n",
       "      <td>examples/synthetic/medium/scenario.yaml</td>\n",
       "      <td>sa</td>\n",
       "      <td>89.370</td>\n",
       "      <td>0.024256</td>\n",
       "      <td>9</td>\n",
       "      <td>89.370</td>\n",
       "      <td>5.0</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>...</td>\n",
       "      <td>user-1</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>heuristic</td>\n",
       "      <td>sa</td>\n",
       "      <td>89.370</td>\n",
       "      <td>0.024256</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>{\"forwarder\": 1.0, \"harvester\": 1.0}</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>user-1</td>\n",
       "      <td>examples/synthetic/large/scenario.yaml</td>\n",
       "      <td>sa</td>\n",
       "      <td>176.808</td>\n",
       "      <td>0.047626</td>\n",
       "      <td>15</td>\n",
       "      <td>176.808</td>\n",
       "      <td>9.0</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>...</td>\n",
       "      <td>user-1</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>heuristic</td>\n",
       "      <td>sa</td>\n",
       "      <td>176.808</td>\n",
       "      <td>0.047626</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>{\"forwarder\": 1.0, \"harvester\": 1.0}</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>4 rows × 38 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "  scenario                            scenario_path solver  objective  \\\n",
       "0   user-1           examples/tiny7/scenario.yaml     sa     13.000   \n",
       "1   user-1   examples/synthetic/small/scenario.yaml     sa     31.492   \n",
       "2   user-1  examples/synthetic/medium/scenario.yaml     sa     89.370   \n",
       "3   user-1   examples/synthetic/large/scenario.yaml     sa    176.808   \n",
       "\n",
       "   runtime_s  assignments  kpi_total_production  kpi_completed_blocks  \\\n",
       "0   0.020893           16                45.500                   1.0   \n",
       "1   0.011216            3                31.492                   3.0   \n",
       "2   0.024256            9                89.370                   5.0   \n",
       "3   0.047626           15               176.808                   9.0   \n",
       "\n",
       "   kpi_mobilisation_cost kpi_mobilisation_cost_by_machine  ... scenario_key  \\\n",
       "0                   65.0                     {\"H2\": 65.0}  ...       user-1   \n",
       "1                    NaN                              NaN  ...       user-1   \n",
       "2                    NaN                              NaN  ...       user-1   \n",
       "3                    NaN                              NaN  ...       user-1   \n",
       "\n",
       "   objective_vs_mip_gap  objective_vs_mip_ratio solver_category  \\\n",
       "0                   NaN                     NaN       heuristic   \n",
       "1                   NaN                     NaN       heuristic   \n",
       "2                   NaN                     NaN       heuristic   \n",
       "3                   NaN                     NaN       heuristic   \n",
       "\n",
       "   best_heuristic_solver  best_heuristic_objective  best_heuristic_runtime_s  \\\n",
       "0                     sa                    13.000                  0.020893   \n",
       "1                     sa                    31.492                  0.011216   \n",
       "2                     sa                    89.370                  0.024256   \n",
       "3                     sa                   176.808                  0.047626   \n",
       "\n",
       "  objective_gap_vs_best_heuristic  runtime_ratio_vs_best_heuristic  \\\n",
       "0                             0.0                              1.0   \n",
       "1                             0.0                              1.0   \n",
       "2                             0.0                              1.0   \n",
       "3                             0.0                              1.0   \n",
       "\n",
       "          kpi_utilisation_ratio_by_role  \n",
       "0                                   NaN  \n",
       "1  {\"forwarder\": 1.0, \"harvester\": 1.0}  \n",
       "2  {\"forwarder\": 1.0, \"harvester\": 1.0}  \n",
       "3  {\"forwarder\": 1.0, \"harvester\": 1.0}  \n",
       "\n",
       "[4 rows x 38 columns]"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import sys\n",
    "from pathlib import Path\n",
    "\n",
    "PROJECT_ROOT = Path.cwd().resolve()\n",
    "while PROJECT_ROOT != PROJECT_ROOT.parent and not (PROJECT_ROOT / \"pyproject.toml\").exists():\n",
    "    PROJECT_ROOT = PROJECT_ROOT.parent\n",
    "if not (PROJECT_ROOT / \"pyproject.toml\").exists():\n",
    "    raise RuntimeError(\n",
    "        \"Notebook must be executed within a FHOPS checkout (pyproject.toml not found).\"\n",
    "    )\n",
    "if str(PROJECT_ROOT) not in sys.path:\n",
    "    sys.path.insert(0, str(PROJECT_ROOT))\n",
    "\n",
    "\n",
    "import pandas as pd\n",
    "\n",
    "SUMMARY_CSV = PROJECT_ROOT / \"docs/examples/analytics/data/benchmark_summary.csv\"\n",
    "summary_df = pd.read_csv(SUMMARY_CSV)\n",
    "summary_df"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02e57593",
   "metadata": {},
   "source": [
    "## Objective vs Scenario"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "70585a87",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-11-14T10:35:06.491676Z",
     "iopub.status.busy": "2025-11-14T10:35:06.491519Z",
     "iopub.status.idle": "2025-11-14T10:35:06.500102Z",
     "shell.execute_reply": "2025-11-14T10:35:06.499494Z"
    }
   },
   "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>objective</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>scenario_path</th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>examples/tiny7/scenario.yaml</th>\n",
       "      <td>13.000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>examples/synthetic/large/scenario.yaml</th>\n",
       "      <td>176.808</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>examples/synthetic/medium/scenario.yaml</th>\n",
       "      <td>89.370</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>examples/synthetic/small/scenario.yaml</th>\n",
       "      <td>31.492</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                         objective\n",
       "scenario_path                                     \n",
       "examples/tiny7/scenario.yaml              13.000\n",
       "examples/synthetic/large/scenario.yaml     176.808\n",
       "examples/synthetic/medium/scenario.yaml     89.370\n",
       "examples/synthetic/small/scenario.yaml      31.492"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "objective_pivot = summary_df.pivot_table(index=\"scenario_path\", values=\"objective\", aggfunc=\"first\")\n",
    "objective_pivot"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf65f1f3",
   "metadata": {},
   "source": [
    "## Runtime Overview"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "40cbb01b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-11-14T10:35:06.504171Z",
     "iopub.status.busy": "2025-11-14T10:35:06.503396Z",
     "iopub.status.idle": "2025-11-14T10:35:06.515537Z",
     "shell.execute_reply": "2025-11-14T10:35:06.514751Z"
    }
   },
   "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>scenario_path</th>\n",
       "      <th>runtime_s</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>examples/tiny7/scenario.yaml</td>\n",
       "      <td>0.020893</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>examples/synthetic/small/scenario.yaml</td>\n",
       "      <td>0.011216</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>examples/synthetic/medium/scenario.yaml</td>\n",
       "      <td>0.024256</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>examples/synthetic/large/scenario.yaml</td>\n",
       "      <td>0.047626</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                             scenario_path  runtime_s\n",
       "0           examples/tiny7/scenario.yaml   0.020893\n",
       "1   examples/synthetic/small/scenario.yaml   0.011216\n",
       "2  examples/synthetic/medium/scenario.yaml   0.024256\n",
       "3   examples/synthetic/large/scenario.yaml   0.047626"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "runtime_table = summary_df[[\"scenario_path\", \"runtime_s\"]]\n",
    "runtime_table"
   ]
  }
 ],
 "metadata": {
  "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.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
