We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[tune] Handle nan case for AsynchScheduler
To deal with the case of recording nan values i would suggest changing from np.percentile to np.nanpercentile in this line.

https://github.com/ray-project/ray/blob/f7455839bf5686cf990c9e6625c6ada9a3ffd7c8/python/ray/tune/schedulers/async_hyperband.py#L145-L148

As stated in https://docs.scipy.org/doc/numpy/reference/generated/numpy.nanpercentile.html#numpy.nanpercentile any time a nan result is recorded this will result in the cutoff being nan.

>>> array([[10.,  nan,   4.],
      [ 3.,   2.,   1.]])
>>> np.percentile(a, 50)
nan

Ultimately leading to this line evaluating to false, preventing any following trial from stopping. 
https://github.com/ray-project/ray/blob/f7455839bf5686cf990c9e6625c6ada9a3ffd7c8/python/ray/tune/schedulers/async_hyperband.py#L157-L158


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `python/ray/tune/schedulers/async_hyperband.py`
Content:
```
1 import logging
2 import numpy as np
3 
4 from ray.tune.schedulers.trial_scheduler import FIFOScheduler, TrialScheduler
5 
6 logger = logging.getLogger(__name__)
7 
8 
9 class AsyncHyperBandScheduler(FIFOScheduler):
10     """Implements the Async Successive Halving.
11 
12     This should provide similar theoretical performance as HyperBand but
13     avoid straggler issues that HyperBand faces. One implementation detail
14     is when using multiple brackets, trial allocation to bracket is done
15     randomly with over a softmax probability.
16 
17     See https://arxiv.org/abs/1810.05934
18 
19     Args:
20         time_attr (str): A training result attr to use for comparing time.
21             Note that you can pass in something non-temporal such as
22             `training_iteration` as a measure of progress, the only requirement
23             is that the attribute should increase monotonically.
24         metric (str): The training result objective value attribute. Stopping
25             procedures will use this attribute.
26         mode (str): One of {min, max}. Determines whether objective is
27             minimizing or maximizing the metric attribute.
28         max_t (float): max time units per trial. Trials will be stopped after
29             max_t time units (determined by time_attr) have passed.
30         grace_period (float): Only stop trials at least this old in time.
31             The units are the same as the attribute named by `time_attr`.
32         reduction_factor (float): Used to set halving rate and amount. This
33             is simply a unit-less scalar.
34         brackets (int): Number of brackets. Each bracket has a different
35             halving rate, specified by the reduction factor.
36     """
37 
38     def __init__(self,
39                  time_attr="training_iteration",
40                  reward_attr=None,
41                  metric="episode_reward_mean",
42                  mode="max",
43                  max_t=100,
44                  grace_period=1,
45                  reduction_factor=4,
46                  brackets=1):
47         assert max_t > 0, "Max (time_attr) not valid!"
48         assert max_t >= grace_period, "grace_period must be <= max_t!"
49         assert grace_period > 0, "grace_period must be positive!"
50         assert reduction_factor > 1, "Reduction Factor not valid!"
51         assert brackets > 0, "brackets must be positive!"
52         assert mode in ["min", "max"], "`mode` must be 'min' or 'max'!"
53 
54         if reward_attr is not None:
55             mode = "max"
56             metric = reward_attr
57             logger.warning(
58                 "`reward_attr` is deprecated and will be removed in a future "
59                 "version of Tune. "
60                 "Setting `metric={}` and `mode=max`.".format(reward_attr))
61 
62         FIFOScheduler.__init__(self)
63         self._reduction_factor = reduction_factor
64         self._max_t = max_t
65 
66         self._trial_info = {}  # Stores Trial -> Bracket
67 
68         # Tracks state for new trial add
69         self._brackets = [
70             _Bracket(grace_period, max_t, reduction_factor, s)
71             for s in range(brackets)
72         ]
73         self._counter = 0  # for
74         self._num_stopped = 0
75         self._metric = metric
76         if mode == "max":
77             self._metric_op = 1.
78         elif mode == "min":
79             self._metric_op = -1.
80         self._time_attr = time_attr
81 
82     def on_trial_add(self, trial_runner, trial):
83         sizes = np.array([len(b._rungs) for b in self._brackets])
84         probs = np.e**(sizes - sizes.max())
85         normalized = probs / probs.sum()
86         idx = np.random.choice(len(self._brackets), p=normalized)
87         self._trial_info[trial.trial_id] = self._brackets[idx]
88 
89     def on_trial_result(self, trial_runner, trial, result):
90         action = TrialScheduler.CONTINUE
91         if self._time_attr not in result or self._metric not in result:
92             return action
93         if result[self._time_attr] >= self._max_t:
94             action = TrialScheduler.STOP
95         else:
96             bracket = self._trial_info[trial.trial_id]
97             action = bracket.on_result(trial, result[self._time_attr],
98                                        self._metric_op * result[self._metric])
99         if action == TrialScheduler.STOP:
100             self._num_stopped += 1
101         return action
102 
103     def on_trial_complete(self, trial_runner, trial, result):
104         if self._time_attr not in result or self._metric not in result:
105             return
106         bracket = self._trial_info[trial.trial_id]
107         bracket.on_result(trial, result[self._time_attr],
108                           self._metric_op * result[self._metric])
109         del self._trial_info[trial.trial_id]
110 
111     def on_trial_remove(self, trial_runner, trial):
112         del self._trial_info[trial.trial_id]
113 
114     def debug_string(self):
115         out = "Using AsyncHyperBand: num_stopped={}".format(self._num_stopped)
116         out += "\n" + "\n".join([b.debug_str() for b in self._brackets])
117         return out
118 
119 
120 class _Bracket():
121     """Bookkeeping system to track the cutoffs.
122 
123     Rungs are created in reversed order so that we can more easily find
124     the correct rung corresponding to the current iteration of the result.
125 
126     Example:
127         >>> b = _Bracket(1, 10, 2, 3)
128         >>> b.on_result(trial1, 1, 2)  # CONTINUE
129         >>> b.on_result(trial2, 1, 4)  # CONTINUE
130         >>> b.cutoff(b._rungs[-1][1]) == 3.0  # rungs are reversed
131         >>> b.on_result(trial3, 1, 1)  # STOP
132         >>> b.cutoff(b._rungs[0][1]) == 2.0
133     """
134 
135     def __init__(self, min_t, max_t, reduction_factor, s):
136         self.rf = reduction_factor
137         MAX_RUNGS = int(np.log(max_t / min_t) / np.log(self.rf) - s + 1)
138         self._rungs = [(min_t * self.rf**(k + s), {})
139                        for k in reversed(range(MAX_RUNGS))]
140 
141     def cutoff(self, recorded):
142         if not recorded:
143             return None
144         return np.percentile(list(recorded.values()), (1 - 1 / self.rf) * 100)
145 
146     def on_result(self, trial, cur_iter, cur_rew):
147         action = TrialScheduler.CONTINUE
148         for milestone, recorded in self._rungs:
149             if cur_iter < milestone or trial.trial_id in recorded:
150                 continue
151             else:
152                 cutoff = self.cutoff(recorded)
153                 if cutoff is not None and cur_rew < cutoff:
154                     action = TrialScheduler.STOP
155                 if cur_rew is None:
156                     logger.warning("Reward attribute is None! Consider"
157                                    " reporting using a different field.")
158                 else:
159                     recorded[trial.trial_id] = cur_rew
160                 break
161         return action
162 
163     def debug_str(self):
164         iters = " | ".join([
165             "Iter {:.3f}: {}".format(milestone, self.cutoff(recorded))
166             for milestone, recorded in self._rungs
167         ])
168         return "Bracket: " + iters
169 
170 
171 ASHAScheduler = AsyncHyperBandScheduler
172 
173 if __name__ == "__main__":
174     sched = AsyncHyperBandScheduler(
175         grace_period=1, max_t=10, reduction_factor=2)
176     print(sched.debug_string())
177     bracket = sched._brackets[0]
178     print(bracket.cutoff({str(i): i for i in range(20)}))
179
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/python/ray/tune/schedulers/async_hyperband.py b/python/ray/tune/schedulers/async_hyperband.py
--- a/python/ray/tune/schedulers/async_hyperband.py
+++ b/python/ray/tune/schedulers/async_hyperband.py
@@ -141,7 +141,8 @@
     def cutoff(self, recorded):
         if not recorded:
             return None
-        return np.percentile(list(recorded.values()), (1 - 1 / self.rf) * 100)
+        return np.nanpercentile(
+            list(recorded.values()), (1 - 1 / self.rf) * 100)
 
     def on_result(self, trial, cur_iter, cur_rew):
         action = TrialScheduler.CONTINUE

{"golden_diff": "diff --git a/python/ray/tune/schedulers/async_hyperband.py b/python/ray/tune/schedulers/async_hyperband.py\n--- a/python/ray/tune/schedulers/async_hyperband.py\n+++ b/python/ray/tune/schedulers/async_hyperband.py\n@@ -141,7 +141,8 @@\n     def cutoff(self, recorded):\n         if not recorded:\n             return None\n-        return np.percentile(list(recorded.values()), (1 - 1 / self.rf) * 100)\n+        return np.nanpercentile(\n+            list(recorded.values()), (1 - 1 / self.rf) * 100)\n \n     def on_result(self, trial, cur_iter, cur_rew):\n         action = TrialScheduler.CONTINUE\n", "issue": "[tune] Handle nan case for AsynchScheduler\nTo deal with the case of recording nan values i would suggest changing from np.percentile to np.nanpercentile in this line.\r\n\r\nhttps://github.com/ray-project/ray/blob/f7455839bf5686cf990c9e6625c6ada9a3ffd7c8/python/ray/tune/schedulers/async_hyperband.py#L145-L148\r\n\r\nAs stated in https://docs.scipy.org/doc/numpy/reference/generated/numpy.nanpercentile.html#numpy.nanpercentile any time a nan result is recorded this will result in the cutoff being nan.\r\n\r\n>>> array([[10.,  nan,   4.],\r\n      [ 3.,   2.,   1.]])\r\n>>> np.percentile(a, 50)\r\nnan\r\n\r\nUltimately leading to this line evaluating to false, preventing any following trial from stopping. \r\nhttps://github.com/ray-project/ray/blob/f7455839bf5686cf990c9e6625c6ada9a3ffd7c8/python/ray/tune/schedulers/async_hyperband.py#L157-L158\r\n\n", "before_files": [{"content": "import logging\nimport numpy as np\n\nfrom ray.tune.schedulers.trial_scheduler import FIFOScheduler, TrialScheduler\n\nlogger = logging.getLogger(__name__)\n\n\nclass AsyncHyperBandScheduler(FIFOScheduler):\n    \"\"\"Implements the Async Successive Halving.\n\n    This should provide similar theoretical performance as HyperBand but\n    avoid straggler issues that HyperBand faces. One implementation detail\n    is when using multiple brackets, trial allocation to bracket is done\n    randomly with over a softmax probability.\n\n    See https://arxiv.org/abs/1810.05934\n\n    Args:\n        time_attr (str): A training result attr to use for comparing time.\n            Note that you can pass in something non-temporal such as\n            `training_iteration` as a measure of progress, the only requirement\n            is that the attribute should increase monotonically.\n        metric (str): The training result objective value attribute. Stopping\n            procedures will use this attribute.\n        mode (str): One of {min, max}. Determines whether objective is\n            minimizing or maximizing the metric attribute.\n        max_t (float): max time units per trial. Trials will be stopped after\n            max_t time units (determined by time_attr) have passed.\n        grace_period (float): Only stop trials at least this old in time.\n            The units are the same as the attribute named by `time_attr`.\n        reduction_factor (float): Used to set halving rate and amount. This\n            is simply a unit-less scalar.\n        brackets (int): Number of brackets. Each bracket has a different\n            halving rate, specified by the reduction factor.\n    \"\"\"\n\n    def __init__(self,\n                 time_attr=\"training_iteration\",\n                 reward_attr=None,\n                 metric=\"episode_reward_mean\",\n                 mode=\"max\",\n                 max_t=100,\n                 grace_period=1,\n                 reduction_factor=4,\n                 brackets=1):\n        assert max_t > 0, \"Max (time_attr) not valid!\"\n        assert max_t >= grace_period, \"grace_period must be <= max_t!\"\n        assert grace_period > 0, \"grace_period must be positive!\"\n        assert reduction_factor > 1, \"Reduction Factor not valid!\"\n        assert brackets > 0, \"brackets must be positive!\"\n        assert mode in [\"min\", \"max\"], \"`mode` must be 'min' or 'max'!\"\n\n        if reward_attr is not None:\n            mode = \"max\"\n            metric = reward_attr\n            logger.warning(\n                \"`reward_attr` is deprecated and will be removed in a future \"\n                \"version of Tune. \"\n                \"Setting `metric={}` and `mode=max`.\".format(reward_attr))\n\n        FIFOScheduler.__init__(self)\n        self._reduction_factor = reduction_factor\n        self._max_t = max_t\n\n        self._trial_info = {}  # Stores Trial -> Bracket\n\n        # Tracks state for new trial add\n        self._brackets = [\n            _Bracket(grace_period, max_t, reduction_factor, s)\n            for s in range(brackets)\n        ]\n        self._counter = 0  # for\n        self._num_stopped = 0\n        self._metric = metric\n        if mode == \"max\":\n            self._metric_op = 1.\n        elif mode == \"min\":\n            self._metric_op = -1.\n        self._time_attr = time_attr\n\n    def on_trial_add(self, trial_runner, trial):\n        sizes = np.array([len(b._rungs) for b in self._brackets])\n        probs = np.e**(sizes - sizes.max())\n        normalized = probs / probs.sum()\n        idx = np.random.choice(len(self._brackets), p=normalized)\n        self._trial_info[trial.trial_id] = self._brackets[idx]\n\n    def on_trial_result(self, trial_runner, trial, result):\n        action = TrialScheduler.CONTINUE\n        if self._time_attr not in result or self._metric not in result:\n            return action\n        if result[self._time_attr] >= self._max_t:\n            action = TrialScheduler.STOP\n        else:\n            bracket = self._trial_info[trial.trial_id]\n            action = bracket.on_result(trial, result[self._time_attr],\n                                       self._metric_op * result[self._metric])\n        if action == TrialScheduler.STOP:\n            self._num_stopped += 1\n        return action\n\n    def on_trial_complete(self, trial_runner, trial, result):\n        if self._time_attr not in result or self._metric not in result:\n            return\n        bracket = self._trial_info[trial.trial_id]\n        bracket.on_result(trial, result[self._time_attr],\n                          self._metric_op * result[self._metric])\n        del self._trial_info[trial.trial_id]\n\n    def on_trial_remove(self, trial_runner, trial):\n        del self._trial_info[trial.trial_id]\n\n    def debug_string(self):\n        out = \"Using AsyncHyperBand: num_stopped={}\".format(self._num_stopped)\n        out += \"\\n\" + \"\\n\".join([b.debug_str() for b in self._brackets])\n        return out\n\n\nclass _Bracket():\n    \"\"\"Bookkeeping system to track the cutoffs.\n\n    Rungs are created in reversed order so that we can more easily find\n    the correct rung corresponding to the current iteration of the result.\n\n    Example:\n        >>> b = _Bracket(1, 10, 2, 3)\n        >>> b.on_result(trial1, 1, 2)  # CONTINUE\n        >>> b.on_result(trial2, 1, 4)  # CONTINUE\n        >>> b.cutoff(b._rungs[-1][1]) == 3.0  # rungs are reversed\n        >>> b.on_result(trial3, 1, 1)  # STOP\n        >>> b.cutoff(b._rungs[0][1]) == 2.0\n    \"\"\"\n\n    def __init__(self, min_t, max_t, reduction_factor, s):\n        self.rf = reduction_factor\n        MAX_RUNGS = int(np.log(max_t / min_t) / np.log(self.rf) - s + 1)\n        self._rungs = [(min_t * self.rf**(k + s), {})\n                       for k in reversed(range(MAX_RUNGS))]\n\n    def cutoff(self, recorded):\n        if not recorded:\n            return None\n        return np.percentile(list(recorded.values()), (1 - 1 / self.rf) * 100)\n\n    def on_result(self, trial, cur_iter, cur_rew):\n        action = TrialScheduler.CONTINUE\n        for milestone, recorded in self._rungs:\n            if cur_iter < milestone or trial.trial_id in recorded:\n                continue\n            else:\n                cutoff = self.cutoff(recorded)\n                if cutoff is not None and cur_rew < cutoff:\n                    action = TrialScheduler.STOP\n                if cur_rew is None:\n                    logger.warning(\"Reward attribute is None! Consider\"\n                                   \" reporting using a different field.\")\n                else:\n                    recorded[trial.trial_id] = cur_rew\n                break\n        return action\n\n    def debug_str(self):\n        iters = \" | \".join([\n            \"Iter {:.3f}: {}\".format(milestone, self.cutoff(recorded))\n            for milestone, recorded in self._rungs\n        ])\n        return \"Bracket: \" + iters\n\n\nASHAScheduler = AsyncHyperBandScheduler\n\nif __name__ == \"__main__\":\n    sched = AsyncHyperBandScheduler(\n        grace_period=1, max_t=10, reduction_factor=2)\n    print(sched.debug_string())\n    bracket = sched._brackets[0]\n    print(bracket.cutoff({str(i): i for i in range(20)}))\n", "path": "python/ray/tune/schedulers/async_hyperband.py"}], "after_files": [{"content": "import logging\nimport numpy as np\n\nfrom ray.tune.schedulers.trial_scheduler import FIFOScheduler, TrialScheduler\n\nlogger = logging.getLogger(__name__)\n\n\nclass AsyncHyperBandScheduler(FIFOScheduler):\n    \"\"\"Implements the Async Successive Halving.\n\n    This should provide similar theoretical performance as HyperBand but\n    avoid straggler issues that HyperBand faces. One implementation detail\n    is when using multiple brackets, trial allocation to bracket is done\n    randomly with over a softmax probability.\n\n    See https://arxiv.org/abs/1810.05934\n\n    Args:\n        time_attr (str): A training result attr to use for comparing time.\n            Note that you can pass in something non-temporal such as\n            `training_iteration` as a measure of progress, the only requirement\n            is that the attribute should increase monotonically.\n        metric (str): The training result objective value attribute. Stopping\n            procedures will use this attribute.\n        mode (str): One of {min, max}. Determines whether objective is\n            minimizing or maximizing the metric attribute.\n        max_t (float): max time units per trial. Trials will be stopped after\n            max_t time units (determined by time_attr) have passed.\n        grace_period (float): Only stop trials at least this old in time.\n            The units are the same as the attribute named by `time_attr`.\n        reduction_factor (float): Used to set halving rate and amount. This\n            is simply a unit-less scalar.\n        brackets (int): Number of brackets. Each bracket has a different\n            halving rate, specified by the reduction factor.\n    \"\"\"\n\n    def __init__(self,\n                 time_attr=\"training_iteration\",\n                 reward_attr=None,\n                 metric=\"episode_reward_mean\",\n                 mode=\"max\",\n                 max_t=100,\n                 grace_period=1,\n                 reduction_factor=4,\n                 brackets=1):\n        assert max_t > 0, \"Max (time_attr) not valid!\"\n        assert max_t >= grace_period, \"grace_period must be <= max_t!\"\n        assert grace_period > 0, \"grace_period must be positive!\"\n        assert reduction_factor > 1, \"Reduction Factor not valid!\"\n        assert brackets > 0, \"brackets must be positive!\"\n        assert mode in [\"min\", \"max\"], \"`mode` must be 'min' or 'max'!\"\n\n        if reward_attr is not None:\n            mode = \"max\"\n            metric = reward_attr\n            logger.warning(\n                \"`reward_attr` is deprecated and will be removed in a future \"\n                \"version of Tune. \"\n                \"Setting `metric={}` and `mode=max`.\".format(reward_attr))\n\n        FIFOScheduler.__init__(self)\n        self._reduction_factor = reduction_factor\n        self._max_t = max_t\n\n        self._trial_info = {}  # Stores Trial -> Bracket\n\n        # Tracks state for new trial add\n        self._brackets = [\n            _Bracket(grace_period, max_t, reduction_factor, s)\n            for s in range(brackets)\n        ]\n        self._counter = 0  # for\n        self._num_stopped = 0\n        self._metric = metric\n        if mode == \"max\":\n            self._metric_op = 1.\n        elif mode == \"min\":\n            self._metric_op = -1.\n        self._time_attr = time_attr\n\n    def on_trial_add(self, trial_runner, trial):\n        sizes = np.array([len(b._rungs) for b in self._brackets])\n        probs = np.e**(sizes - sizes.max())\n        normalized = probs / probs.sum()\n        idx = np.random.choice(len(self._brackets), p=normalized)\n        self._trial_info[trial.trial_id] = self._brackets[idx]\n\n    def on_trial_result(self, trial_runner, trial, result):\n        action = TrialScheduler.CONTINUE\n        if self._time_attr not in result or self._metric not in result:\n            return action\n        if result[self._time_attr] >= self._max_t:\n            action = TrialScheduler.STOP\n        else:\n            bracket = self._trial_info[trial.trial_id]\n            action = bracket.on_result(trial, result[self._time_attr],\n                                       self._metric_op * result[self._metric])\n        if action == TrialScheduler.STOP:\n            self._num_stopped += 1\n        return action\n\n    def on_trial_complete(self, trial_runner, trial, result):\n        if self._time_attr not in result or self._metric not in result:\n            return\n        bracket = self._trial_info[trial.trial_id]\n        bracket.on_result(trial, result[self._time_attr],\n                          self._metric_op * result[self._metric])\n        del self._trial_info[trial.trial_id]\n\n    def on_trial_remove(self, trial_runner, trial):\n        del self._trial_info[trial.trial_id]\n\n    def debug_string(self):\n        out = \"Using AsyncHyperBand: num_stopped={}\".format(self._num_stopped)\n        out += \"\\n\" + \"\\n\".join([b.debug_str() for b in self._brackets])\n        return out\n\n\nclass _Bracket():\n    \"\"\"Bookkeeping system to track the cutoffs.\n\n    Rungs are created in reversed order so that we can more easily find\n    the correct rung corresponding to the current iteration of the result.\n\n    Example:\n        >>> b = _Bracket(1, 10, 2, 3)\n        >>> b.on_result(trial1, 1, 2)  # CONTINUE\n        >>> b.on_result(trial2, 1, 4)  # CONTINUE\n        >>> b.cutoff(b._rungs[-1][1]) == 3.0  # rungs are reversed\n        >>> b.on_result(trial3, 1, 1)  # STOP\n        >>> b.cutoff(b._rungs[0][1]) == 2.0\n    \"\"\"\n\n    def __init__(self, min_t, max_t, reduction_factor, s):\n        self.rf = reduction_factor\n        MAX_RUNGS = int(np.log(max_t / min_t) / np.log(self.rf) - s + 1)\n        self._rungs = [(min_t * self.rf**(k + s), {})\n                       for k in reversed(range(MAX_RUNGS))]\n\n    def cutoff(self, recorded):\n        if not recorded:\n            return None\n        return np.nanpercentile(\n            list(recorded.values()), (1 - 1 / self.rf) * 100)\n\n    def on_result(self, trial, cur_iter, cur_rew):\n        action = TrialScheduler.CONTINUE\n        for milestone, recorded in self._rungs:\n            if cur_iter < milestone or trial.trial_id in recorded:\n                continue\n            else:\n                cutoff = self.cutoff(recorded)\n                if cutoff is not None and cur_rew < cutoff:\n                    action = TrialScheduler.STOP\n                if cur_rew is None:\n                    logger.warning(\"Reward attribute is None! Consider\"\n                                   \" reporting using a different field.\")\n                else:\n                    recorded[trial.trial_id] = cur_rew\n                break\n        return action\n\n    def debug_str(self):\n        iters = \" | \".join([\n            \"Iter {:.3f}: {}\".format(milestone, self.cutoff(recorded))\n            for milestone, recorded in self._rungs\n        ])\n        return \"Bracket: \" + iters\n\n\nASHAScheduler = AsyncHyperBandScheduler\n\nif __name__ == \"__main__\":\n    sched = AsyncHyperBandScheduler(\n        grace_period=1, max_t=10, reduction_factor=2)\n    print(sched.debug_string())\n    bracket = sched._brackets[0]\n    print(bracket.cutoff({str(i): i for i in range(20)}))\n", "path": "python/ray/tune/schedulers/async_hyperband.py"}]}