From c34da35debc984f416310f34e3deb8da6a19e786 Mon Sep 17 00:00:00 2001 From: Nolwen Date: Mon, 7 Oct 2024 13:29:20 +0200 Subject: [PATCH] Update scheduling notebook to use callback to time-out a solver --- notebooks/13_scheduling_tuto.ipynb | 73 +++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/notebooks/13_scheduling_tuto.ipynb b/notebooks/13_scheduling_tuto.ipynb index d132864406..558cde494d 100644 --- a/notebooks/13_scheduling_tuto.ipynb +++ b/notebooks/13_scheduling_tuto.ipynb @@ -655,6 +655,74 @@ "metadata": {}, "outputs": [], "source": [ + "import time\n", + "\n", + "from skdecide.hub.solver.lazy_astar import LazyAstar\n", + "\n", + "\n", + "# Implement a callback to time-out\n", + "class TimeoutCallback:\n", + " \"\"\"Callback to stop the solve process after a given time.\n", + "\n", + " Stops the solve process if a limit training time has been elapsed.\n", + " This time is checked after each `check_nb_steps` steps.\n", + "\n", + " \"\"\"\n", + "\n", + " def __init__(self, total_seconds: int, check_nb_steps: int = 1):\n", + " \"\"\"\n", + "\n", + " Args:\n", + " total_seconds: Total time in seconds allowed to solve\n", + " check_nb_steps: Number of steps to wait before next time check\n", + "\n", + " \"\"\"\n", + " self.total_seconds = total_seconds\n", + " self.check_nb_steps = check_nb_steps\n", + " self.starting_time = time.perf_counter()\n", + " self.step = 0\n", + "\n", + " def __call__(self, solver) -> bool:\n", + " \"\"\"Called at each solve iteration.\n", + "\n", + " If returning True, the solve process is stopped.\n", + "\n", + " \"\"\"\n", + " if self.step % self.check_nb_steps == 0:\n", + " current_time = time.perf_counter()\n", + " difference = current_time - self.starting_time\n", + " logging.debug(\n", + " f\"step {self.step}: {difference} seconds elapsed since solve start.\"\n", + " )\n", + " if difference >= self.total_seconds:\n", + " logging.info(\n", + " f\"{self.__class__.__name__} stops the solve process before it could finish.\"\n", + " )\n", + " return True\n", + " self.step += 1\n", + " return False\n", + "\n", + "\n", + "# Solve with lazy A* and the time-out callback\n", + "solver = LazyAstar(\n", + " domain_factory=lambda: domain,\n", + " heuristic=None,\n", + " callback=TimeoutCallback(total_seconds=300, check_nb_steps=500),\n", + ")\n", + "solver.solve(from_memory=state)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note about how to time-out:** \n", + "\n", + "We use here a callback that is called at each iteration of the solve process to manage the time-out. As Lazy A* iterations are very fast (~ 1000 / second), we choose to check the timer every 500 steps. \n", + "This would not work on other solver with bigger iterations. So be careful to update this number to use it with a different solver.\n", + "\n", + "Another solution could be to use the signal python package, but it would not work on windows. It would be something like the code below:\n", + "```python\n", "import signal\n", "\n", "from skdecide.hub.solver.lazy_astar import LazyAstar\n", @@ -673,9 +741,10 @@ "try:\n", " solver.solve(from_memory=state)\n", "except Exception:\n", - " print(\"the algorithm could not finish\")\n", + " print(\"The solve process was stopped befor it could finish.\")\n", "finally:\n", - " signal.alarm(0)" + " signal.alarm(0)\n", + "```\n" ] }, {