class_docstr: Convert trial to one or more task parameters.
  
  How trial is mapped to parameter is specified with a map like
  {parameter_name: {trial_index: level name}}.
  For example,
  {"trial_param1": {0: "level1", 1: "level1", 2: "level2"},}
  will create choice parameters "trial_param1" with is_task=True.
  Observations with trial 0 or 1 will have "trial_param1" set to "level1",
  and those with trial 2 will have "trial_param1" set to "level2". Multiple
  parameter names and mappings can be specified in this dict.
  
  The trial level mapping can be specified in config["trial_level_map"]. If
  not specified, defaults to a parameter with a level for every trial index.
  
  For the reverse transform, if there are multiple mappings in the transform
  the trial will not be set.
  
  The created parameter will be given a target value that will default to the
  lowest trial index in the mapping, or can be provided in config["target_trial"].
  
  Will raise if trial not specified for every point in the training data.
  
  Transform is done in-place.
code: def _transform_search_space(
      self, search_space: SearchSpace
  ) -> SearchSpace:
      for p_name, level_dict in self.trial_level_map.items():
          level_values = sorted(set(level_dict.values()))
          if len(level_values) < 2:
              details = (
                  f"only 1 found: {level_values}"
                  if level_values
                  else "none found"
              )
              raise ValueError(
                  f"TrialAsTask transform expects 2+ task params, {details}"
              )
          is_int = all(isinstance(val, int) for val in level_values)
          trial_param = ChoiceParameter(
              name=p_name,
              parameter_type=ParameterType.INT
              if is_int
              else ParameterType.STRING,
              values=level_values,  # pyre-fixme [6]
              # if all values are integers, retain the original order
              # they are encoded in TaskEncode
              is_ordered=is_int,
              is_task=True,
              sort_values=True,
              target_value=self.target_values[p_name],
          )
          search_space.add_parameter(trial_param)
      return search_space
  
file_path: Ax/ax/modelbridge/transforms/trial_as_task.py
imports: from logging import Logger
  from typing import Dict, List, Optional, TYPE_CHECKING, Union
  from ax.core.observation import Observation, ObservationFeatures
  from ax.core.parameter import ChoiceParameter, ParameterType
  from ax.core.search_space import RobustSearchSpace, SearchSpace
  from ax.exceptions.core import UnsupportedError
  from ax.modelbridge.transforms.base import Transform
  from ax.models.types import TConfig
  from ax.utils.common.logger import get_logger
label_desc: Use image node_id 3 for calling the TrialAsTask obj's underlying member method code with example usage: obj._transform_search_space(search_space) and returns: search_space