Benchmark Summary Notebook
Summarise solver performance across multiple benchmark scenarios.
[1]:
import sys
from pathlib import Path
PROJECT_ROOT = Path.cwd().resolve()
while PROJECT_ROOT != PROJECT_ROOT.parent and not (PROJECT_ROOT / "pyproject.toml").exists():
PROJECT_ROOT = PROJECT_ROOT.parent
if not (PROJECT_ROOT / "pyproject.toml").exists():
raise RuntimeError(
"Notebook must be executed within a FHOPS checkout (pyproject.toml not found)."
)
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
import pandas as pd
SUMMARY_CSV = PROJECT_ROOT / "docs/examples/analytics/data/benchmark_summary.csv"
summary_df = pd.read_csv(SUMMARY_CSV)
summary_df
[1]:
| scenario | scenario_path | solver | objective | runtime_s | assignments | kpi_total_production | kpi_completed_blocks | kpi_mobilisation_cost | kpi_mobilisation_cost_by_machine | ... | scenario_key | objective_vs_mip_gap | objective_vs_mip_ratio | solver_category | best_heuristic_solver | best_heuristic_objective | best_heuristic_runtime_s | objective_gap_vs_best_heuristic | runtime_ratio_vs_best_heuristic | kpi_utilisation_ratio_by_role | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | user-1 | examples/tiny7/scenario.yaml | sa | 13.000 | 0.020893 | 16 | 45.500 | 1.0 | 65.0 | {"H2": 65.0} | ... | user-1 | NaN | NaN | heuristic | sa | 13.000 | 0.020893 | 0.0 | 1.0 | NaN |
| 1 | user-1 | examples/synthetic/small/scenario.yaml | sa | 31.492 | 0.011216 | 3 | 31.492 | 3.0 | NaN | NaN | ... | user-1 | NaN | NaN | heuristic | sa | 31.492 | 0.011216 | 0.0 | 1.0 | {"forwarder": 1.0, "harvester": 1.0} |
| 2 | user-1 | examples/synthetic/medium/scenario.yaml | sa | 89.370 | 0.024256 | 9 | 89.370 | 5.0 | NaN | NaN | ... | user-1 | NaN | NaN | heuristic | sa | 89.370 | 0.024256 | 0.0 | 1.0 | {"forwarder": 1.0, "harvester": 1.0} |
| 3 | user-1 | examples/synthetic/large/scenario.yaml | sa | 176.808 | 0.047626 | 15 | 176.808 | 9.0 | NaN | NaN | ... | user-1 | NaN | NaN | heuristic | sa | 176.808 | 0.047626 | 0.0 | 1.0 | {"forwarder": 1.0, "harvester": 1.0} |
4 rows × 38 columns
Objective vs Scenario
[2]:
objective_pivot = summary_df.pivot_table(index="scenario_path", values="objective", aggfunc="first")
objective_pivot
[2]:
| objective | |
|---|---|
| scenario_path | |
| examples/synthetic/large/scenario.yaml | 176.808 |
| examples/synthetic/medium/scenario.yaml | 89.370 |
| examples/synthetic/small/scenario.yaml | 31.492 |
| examples/tiny7/scenario.yaml | 13.000 |
Runtime Overview
[3]:
runtime_table = summary_df[["scenario_path", "runtime_s"]]
runtime_table
[3]:
| scenario_path | runtime_s | |
|---|---|---|
| 0 | examples/tiny7/scenario.yaml | 0.020893 |
| 1 | examples/synthetic/small/scenario.yaml | 0.011216 |
| 2 | examples/synthetic/medium/scenario.yaml | 0.024256 |
| 3 | examples/synthetic/large/scenario.yaml | 0.047626 |