{
  "nbformat": 4,
  "nbformat_minor": 5,
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.12.14"
    },
    "research_runtime": {
      "engine": "pyodide",
      "packages": [],
      "assets": [
        "experiment.py",
        "figure_generation.py"
      ],
      "generated_assets": [
        "results.json",
        "figure.svg"
      ],
      "display_assets": [
        "figure.svg"
      ],
      "filesystem_root": ".",
      "network_required": false,
      "validation_engine": "CPython standard-library execution"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Can a scheduler learn to pack two resources at once?\n\nThree deterministic scheduling rules and exact reward accounting on a synthetic two-resource workload; no learned policy or production scheduler benchmark.\n\nThis notebook runs the complete saved experiment, checks its assertions, and regenerates the SVG from the computed results. Python 3.10+ and standard-library modules only. Place experiment.py and figure_generation.py beside the notebook. The exact loaded assets are recorded in notebook metadata.\n"
      ],
      "id": "cell-1"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "execution_count": 1,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "FIFO: finish={'A': 2, 'B': 3, 'C': 4} mean_slowdown=2.000 reward=-6.000\n",
            "scan: finish={'A': 2, 'B': 3, 'C': 2} mean_slowdown=1.667 reward=-5.000\n",
            "shortest: finish={'A': 3, 'B': 1, 'C': 2} mean_slowdown=1.167 reward=-3.500\n",
            "Capacity sweep checked all six scan orders at each of 16 CPU/memory combinations.\n",
            "Every schedule obeys both capacity constraints and exactly reconciles cumulative reward with total slowdown.\n"
          ]
        }
      ],
      "source": [
        "import runpy\n_ = runpy.run_path('experiment.py', run_name='__main__')\n"
      ],
      "id": "cell-2"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "execution_count": 2,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Regenerated figure.svg from results.json.\n"
          ]
        }
      ],
      "source": [
        "runpy.run_path('figure_generation.py', run_name='__main__')\n",
        "print('Regenerated figure.svg from results.json.')\n",
        "\n",
        "import base64\n",
        "print('__NOTEBOOK_IMAGE__svg+xml:' + base64.b64encode(open('figure.svg','rb').read()).decode())\n"
      ],
      "id": "cell-3"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Inspect the saved result\n\nThe article's static figure is available before running code. The regenerated figure.svg uses results.json, and every plotted quantity comes from the experiment.\n\n![Computed figure](figure.svg)\n\nChange an input in experiment.py, rerun both code cells, then compare the saved result and figure.\n"
      ],
      "id": "cell-4"
    }
  ]
}
