class_docstr: Convert a RangeParameter of type int to type float.
  
  Uses either randomized_rounding or default python rounding,
  depending on 'rounding' flag.
  
  The `min_choices` config can be used to transform only the parameters
  with cardinality greater than or equal to `min_choices`; with the exception
  of `log_scale` parameters, which are always transformed.
  
  Transform is done in-place.
class_docstr_tok: ["Convert","a","RangeParameter","of","type","int","to","type","float",".","Uses","either","randomized_rounding","or","default","python","rounding",",","depending","on","'rounding","'","flag",".","The","`","min_choices","`","config","can","be","used","to","transform","only","the","parameters","with","cardinality","greater","than","or","equal","to","`","min_choices","`",";","with","the","exception","of","`","log_scale","`","parameters",",","which","are","always","transformed",".","Transform","is","done","in-place","."]
code: def untransform_observation_features(
      self, observation_features: List[ObservationFeatures]
  ) -> List[ObservationFeatures]:
      for obsf in observation_features:
          present_params = self.transform_parameters.intersection(
              obsf.parameters.keys()
          )
          if self.rounding == "strict":
              for p_name in present_params:
                  # pyre: param is declared to have type `float` but is used as
                  # pyre-fixme[9]: type `Optional[typing.Union[bool, float, str]]`.
                  param: float = obsf.parameters.get(p_name)
                  obsf.parameters[p_name] = int(
                      round(param)
                  )  # TODO: T41938776
          else:
              if self.contains_constrained_integer:
                  if len(present_params) == 0:
                      continue
                  elif len(present_params) != len(
                      self.transform_parameters
                  ):
                      # no parameters being present is allowed to handle fixed
                      # features, but all parameters must be present if there
                      # are parameter constraints involving integers.
                      raise ValueError(
                          "Either all parameters must be provided or no parameters"
                          " should be provided, when there are parameter"
                          " constraints involving integers."
                      )
              round_attempts = 0
              rounded_parameters = randomized_round_parameters(
                  obsf.parameters, self.transform_parameters
              )
              # Try to round up to max_round_attempt times)
              while (
                  not self.search_space.check_membership(
                      rounded_parameters,
                      check_all_parameters_present=False,
                  )
                  and round_attempts < self.max_round_attempts
              ):
                  rounded_parameters = randomized_round_parameters(
                      obsf.parameters, present_params
                  )
                  round_attempts += 1
              if not self.search_space.check_membership(
                  rounded_parameters, check_all_parameters_present=False
              ):
                  logger.warning(
                      f"Unable to round {obsf.parameters}"
                      f"to meet parameter constraints of {self.search_space}"
                  )
                  # This means we failed to randomly round the observation to
                  # something that satisfies the search space bounds and parameter
                  # constraints. We use strict rounding in order to get a candidate
                  # that satisfies the search space bounds, but this candidate may
                  # not satisfy the parameter constraints.
                  for p_name in present_params:
                      param = obsf.parameters.get(p_name)
                      obsf.parameters[p_name] = int(
                          round(param)
                      )  # pyre-ignore
              else:  # Update observation if rounding was successful
                  for p_name in present_params:
                      obsf.parameters[p_name] = rounded_parameters[
                          p_name
                      ]
  
      return observation_features
  
file_path: Ax/ax/modelbridge/transforms/int_to_float.py
imports: from logging import Logger
  from typing import Dict, List, Optional, Set, TYPE_CHECKING
  from ax.core.observation import Observation, ObservationFeatures
  from ax.core.parameter import Parameter, ParameterType, RangeParameter
  from ax.core.search_space import SearchSpace
  from ax.modelbridge.transforms.base import Transform
  from ax.modelbridge.transforms.rounding import contains_constrained_integer, randomized_round_parameters
  from ax.modelbridge.transforms.utils import construct_new_search_space
  from ax.models.types import TConfig
  from ax.utils.common.logger import get_logger
  from ax.utils.common.typeutils import checked_cast, not_none
label_desc: Use image node_id 4 for calling the IntToFloat obj's underlying member method code with example usage: obj.untransform_observation_features(observation_features) and returns: observation_features