class_docstr: `Hyperband <https://arxiv.org/pdf/1603.06560.pdf>`__ is a multi-fidelity hyperparameter tuning algorithm
  based on successive halving.
  
  The basic idea of Hyperband is to create several buckets,
  each having ``n`` randomly generated hyperparameter configurations,
  each configuration using ``r`` resources (e.g., epoch number, batch number).
  After the ``n`` configurations are finished, it chooses the top ``n/eta`` configurations
  and runs them using increased ``r*eta`` resources.
  At last, it chooses the best configuration it has found so far.
  Please refer to the paper :footcite:t:`li2017hyperband` for detailed algorithm.
  
  Examples
  --------
  
  .. code-block::
  
      config.tuner.name = 'Hyperband'
      config.tuner.class_args = {
          'optimize_mode': 'maximize',
          'R': 60,
          'eta': 3
      }
  
  
  Note that once you use Advisor, you are not allowed to add a Tuner and Assessor spec in the config file.
  When Hyperband is used, the dict returned by :func:`nni.get_next_parameter` one more key
  called ``TRIAL_BUDGET`` besides the hyperparameters and their values.
  **With this TRIAL_BUDGET, users can control in trial code how long a trial runs by following
  the suggested trial budget from Hyperband.** ``TRIAL_BUDGET`` is a relative number,
  users can interpret them as number of epochs, number of mini-batches, running time, etc.
  
  Here is a concrete example of ``R=81`` and ``eta=3``:
  
  .. list-table::
      :header-rows: 1
      :widths: auto
  
      * -
        - s=4
        - s=3
        - s=2
        - s=1
        - s=0
      * - i
        - n r
        - n r
        - n r
        - n r
        - n r
      * - 0
        - 81 1
        - 27 3
        - 9 9
        - 6 27
        - 5 81
      * - 1
        - 27 3
        - 9 9
        - 3 27
        - 2 81
        -
      * - 2
        - 9 9
        - 3 27
        - 1 81
        -
        -
      * - 3
        - 3 27
        - 1 81
        -
        -
        -
      * - 4
        - 1 81
        -
        -
        -
        -
  
  
  ``s`` means bucket, ``n`` means the number of configurations that are generated,
  the corresponding ``r`` means how many budgets these configurations run.
  ``i`` means round, for example, bucket 4 has 5 rounds, bucket 3 has 4 rounds.
  
  A complete example can be found :githublink:`examples/trials/mnist-advisor`.
  
  Parameters
  ----------
  optimize_mode: str
      Optimize mode, 'maximize' or 'minimize'.
  
  R: int
      The maximum amount of budget that can be allocated to a single configuration.
      Here, trial budget could mean the number of epochs, number of mini-batches, etc.,
      depending on how users interpret it.
      Each trial should use ``TRIAL_BUDGET`` to control how long it runs.
  
  eta: int
      The variable that controls the proportion of configurations discarded in each round of SuccessiveHalving.
      ``1/eta`` configurations will survive and rerun using more budgets in each round.
  
  exec_mode: str
      Execution mode, 'serial' or 'parallelism'.
      If 'parallelism', the tuner will try to use available resources to start new bucket immediately.
      If 'serial', the tuner will only start new bucket after the current bucket is done.
  
  
  Notes
  -----
  
  First, Hyperband an example of how to write an autoML algorithm based on MsgDispatcherBase,
  rather than based on Tuner and Assessor. Hyperband is implemented in this way
  because it integrates the functions of both Tuner and Assessor,thus, we call it Advisor.
  
  Second, this implementation fully leverages Hyperband's internal parallelism.
  Specifically, the next bucket is not started strictly after the current bucket.
  Instead, it starts when there are available resources. If you want to use full parallelism mode,
  set ``exec_mode`` to ``parallelism``.
  
  Or if you want to set ``exec_mode`` with ``serial`` according to the original algorithm.
  In this mode, the next bucket will start strictly after the current bucket.
  
  ``parallelism`` mode may lead to multiple unfinished buckets,
  in contrast, there is at most one unfinished bucket under ``serial`` mode.
  The advantage of ``parallelism`` mode is to make full use of resources,
  which may reduce the experiment duration multiple times.
docstr: Parameters
  ----------
  data: dict()
      it has three keys: trial_job_id, event, hyper_params
      trial_job_id: the id generated by training service
      event: the job's state
      hyper_params: the hyperparameters (a string) generated and returned by tuner
docstr_tok: ["Parameters","--","--","--","--","--","data",":","dict","(",")","it","has","three","keys",":","trial_job_id",",","event",",","hyper_params","trial_job_id",":","the","id","generated","by","training","service","event",":","the","job","'s","state","hyper_params",":","the","hyperparameters","(","a","string",")","generated","and","returned","by","tuner"]
code: def handle_trial_end(self, data):
      """
      Parameters
      ----------
      data: dict()
          it has three keys: trial_job_id, event, hyper_params
          trial_job_id: the id generated by training service
          event: the job's state
          hyper_params: the hyperparameters (a string) generated and returned by tuner
      """
      hyper_params = nni.load(data["hyper_params"])
      if self.is_created_in_previous_exp(hyper_params["parameter_id"]):
          # The end of the recovered trial is ignored
          return
      self._handle_trial_end(hyper_params["parameter_id"])
      if data["trial_job_id"] in self.job_id_para_id_map:
          del self.job_id_para_id_map[data["trial_job_id"]]
  
imports: import copy
  import logging
  import math
  import sys
  import numpy
  from schema import Schema, Optional
  import nni
  from nni import ClassArgsValidator
  from nni.common.hpo_utils import validate_search_space
  from nni.runtime.common import multi_phase_enabled
  from nni.runtime.msg_dispatcher_base import MsgDispatcherBase
  from nni.runtime.tuner_command_channel import CommandType
  from nni.utils import NodeType, OptimizeMode, MetricType, extract_scalar_reward
  from nni import parameter_expressions
label_desc: Use image node_id 8 for calling the Hyperband obj's underlying member method code with example usage: obj.handle_trial_end(data) without return types