{ "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": "2026-10-05T12:57:40.320317Z", "iopub.status.busy": "2026-10-05T12:57:40.320162Z", "iopub.status.idle": "2026-10-05T12:57:40.510490Z", "shell.execute_reply": "2026-10-05T12:57:40.509545Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
scenarioscenario_pathsolverobjectiveruntime_sassignmentskpi_total_productionkpi_completed_blockskpi_mobilisation_costkpi_mobilisation_cost_by_machine...scenario_keyobjective_vs_mip_gapobjective_vs_mip_ratiosolver_categorybest_heuristic_solverbest_heuristic_objectivebest_heuristic_runtime_sobjective_gap_vs_best_heuristicruntime_ratio_vs_best_heuristickpi_utilisation_ratio_by_role
0user-1examples/tiny7/scenario.yamlsa13.0000.0208931645.5001.065.0{\"H2\": 65.0}...user-1NaNNaNheuristicsa13.0000.0208930.01.0NaN
1user-1examples/synthetic/small/scenario.yamlsa31.4920.011216331.4923.0NaNNaN...user-1NaNNaNheuristicsa31.4920.0112160.01.0{\"forwarder\": 1.0, \"harvester\": 1.0}
2user-1examples/synthetic/medium/scenario.yamlsa89.3700.024256989.3705.0NaNNaN...user-1NaNNaNheuristicsa89.3700.0242560.01.0{\"forwarder\": 1.0, \"harvester\": 1.0}
3user-1examples/synthetic/large/scenario.yamlsa176.8080.04762615176.8089.0NaNNaN...user-1NaNNaNheuristicsa176.8080.0476260.01.0{\"forwarder\": 1.0, \"harvester\": 1.0}
\n", "

4 rows × 38 columns

\n", "
" ], "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": "2026-10-05T12:57:40.512030Z", "iopub.status.busy": "2026-10-05T12:57:40.511889Z", "iopub.status.idle": "2026-10-05T12:57:40.519452Z", "shell.execute_reply": "2026-10-05T12:57:40.518452Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
objective
scenario_path
examples/synthetic/large/scenario.yaml176.808
examples/synthetic/medium/scenario.yaml89.370
examples/synthetic/small/scenario.yaml31.492
examples/tiny7/scenario.yaml13.000
\n", "
" ], "text/plain": [ " objective\n", "scenario_path \n", "examples/synthetic/large/scenario.yaml 176.808\n", "examples/synthetic/medium/scenario.yaml 89.370\n", "examples/synthetic/small/scenario.yaml 31.492\n", "examples/tiny7/scenario.yaml 13.000" ] }, "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": "2026-10-05T12:57:40.520726Z", "iopub.status.busy": "2026-10-05T12:57:40.520617Z", "iopub.status.idle": "2026-10-05T12:57:40.525440Z", "shell.execute_reply": "2026-10-05T12:57:40.524581Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
scenario_pathruntime_s
0examples/tiny7/scenario.yaml0.020893
1examples/synthetic/small/scenario.yaml0.011216
2examples/synthetic/medium/scenario.yaml0.024256
3examples/synthetic/large/scenario.yaml0.047626
\n", "
" ], "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.11.16" } }, "nbformat": 4, "nbformat_minor": 5 }