code: def exploit_and_explore(
      bot_trial_info,
      top_trial_info,
      factor,
      resample_probability,
      epoch,
      search_space,
  ):
      """
      Replace checkpoint of bot_trial with top, and perturb hyperparameters
  
      Parameters
      ----------
      bot_trial_info : TrialInfo
          bottom model whose parameters should be replaced
      top_trial_info : TrialInfo
          better model
      factor : float
          factor for perturbation
      resample_probability : float
          probability for resampling
      epoch : int
          step of PBTTuner
      search_space : dict
          search_space to keep perturbed hyperparameters in range
      """
      bot_checkpoint_dir = bot_trial_info.checkpoint_dir
      top_hyper_parameters = top_trial_info.hyper_parameters
      hyper_parameters = copy.deepcopy(top_hyper_parameters)
      random_state = np.random.RandomState()
      hyper_parameters["load_checkpoint_dir"] = hyper_parameters[
          "save_checkpoint_dir"
      ]
      hyper_parameters["save_checkpoint_dir"] = os.path.join(
          bot_checkpoint_dir, str(epoch)
      )
      for key in hyper_parameters.keys():
          hyper_parameter = hyper_parameters[key]
          if (
              key == "load_checkpoint_dir"
              or key == "save_checkpoint_dir"
          ):
              continue
          elif search_space[key]["_type"] == "choice":
              choices = search_space[key]["_value"]
              ub, uv = (
                  len(choices) - 1,
                  choices.index(hyper_parameter) + 1,
              )
              lb, lv = 0, choices.index(hyper_parameter) - 1
          elif search_space[key]["_type"] == "randint":
              lb, ub = search_space[key]["_value"][:2]
              ub -= 1
              uv = hyper_parameter + 1
              lv = hyper_parameter - 1
          elif search_space[key]["_type"] == "uniform":
              lb, ub = search_space[key]["_value"][:2]
              perturb = (ub - lb) * factor
              uv = hyper_parameter + perturb
              lv = hyper_parameter - perturb
          elif search_space[key]["_type"] == "quniform":
              lb, ub, q = search_space[key]["_value"][:3]
              multi = round(hyper_parameter / q)
              uv = (multi + 1) * q
              lv = (multi - 1) * q
          elif search_space[key]["_type"] == "loguniform":
              lb, ub = search_space[key]["_value"][:2]
              perturb = (np.log(ub) - np.log(lb)) * factor
              uv = np.exp(
                  min(np.log(hyper_parameter) + perturb, np.log(ub))
              )
              lv = np.exp(
                  max(np.log(hyper_parameter) - perturb, np.log(lb))
              )
          elif search_space[key]["_type"] == "qloguniform":
              lb, ub, q = search_space[key]["_value"][:3]
              multi = round(hyper_parameter / q)
              uv = (multi + 1) * q
              lv = (multi - 1) * q
          elif search_space[key]["_type"] == "normal":
              sigma = search_space[key]["_value"][1]
              perturb = sigma * factor
              uv = ub = hyper_parameter + perturb
              lv = lb = hyper_parameter - perturb
          elif search_space[key]["_type"] == "qnormal":
              q = search_space[key]["_value"][2]
              uv = ub = hyper_parameter + q
              lv = lb = hyper_parameter - q
          elif search_space[key]["_type"] == "lognormal":
              sigma = search_space[key]["_value"][1]
              perturb = sigma * factor
              uv = ub = np.exp(np.log(hyper_parameter) + perturb)
              lv = lb = np.exp(np.log(hyper_parameter) - perturb)
          elif search_space[key]["_type"] == "qlognormal":
              q = search_space[key]["_value"][2]
              uv = ub = hyper_parameter + q
              lv, lb = hyper_parameter - q, 1e-10
          else:
              logger.warning(
                  "Illegal type to perturb: %s",
                  search_space[key]["_type"],
              )
              continue
  
          if search_space[key]["_type"] == "choice":
              idx = perturbation(
                  search_space[key]["_type"],
                  search_space[key]["_value"],
                  resample_probability,
                  uv,
                  ub,
                  lv,
                  lb,
                  random_state,
              )
              hyper_parameters[key] = choices[idx]
          else:
              hyper_parameters[key] = perturbation(
                  search_space[key]["_type"],
                  search_space[key]["_value"],
                  resample_probability,
                  uv,
                  ub,
                  lv,
                  lb,
                  random_state,
              )
      bot_trial_info.hyper_parameters = hyper_parameters
      bot_trial_info.clean_id()
  
imports: import copy
  import logging
  import os
  import random
  import numpy
  from schema import Schema, Optional
  import nni
  from nni import ClassArgsValidator
  import nni.parameter_expressions
  from nni.tuner import Tuner
  from nni.utils import OptimizeMode, extract_scalar_reward, split_index, json2parameter, json2space
label_desc: Use image node_id 2 for calling a global function with example usage: exploit_and_explore(bot_trial_info, top_trial_info, factor, resample_probability, epoch, search_space) without return types