code: def infer_reference_point_from_experiment(
      experiment: Experiment,
  ) -> List[ObjectiveThreshold]:
      """This functions is a wrapper around ``infer_reference_point`` to find the nadir
      point from the pareto front of an experiment. Aside from converting experiment
      to tensors, this wrapper transforms back and forth the objectives of the experiment
      so that they are appropriately used by ``infer_reference_point``.
  
      Args:
          experiment: The experiment for which we want to infer the reference point.
  
      Returns:
          A list of objective thresholds representing the reference point.
      """
      if not experiment.is_moo_problem:
          raise ValueError(
              "This function works for MOO experiments only."
              f" Experiment {experiment.name} is single objective."
          )
  
      # Reading experiment data.
      mb_reference = get_tensor_converter_model(
          experiment=experiment, data=experiment.fetch_data()
      )
      obs_feats, obs_data, _ = _get_modelbridge_training_data(
          modelbridge=mb_reference
      )
  
      # Since objectives could have arbitrary orders in objective_thresholds and
      # further down the road `get_pareto_frontier_and_configs` arbitrarily changes the
      # orders of the objectives, we fix the objective orders here based on the
      # observation_data and maintain it throughout the flow.
      objective_orders = obs_data[0].metric_names
  
      # Defining a dummy reference point so that all observed points are considered
      # when calculating the Pareto front. Also, defining a multiplier to turn all
      # the objectives to be maximized. Note that the multiplier at this point
      # contains 0 for outcome_constraint metrics, but this will be dropped later.
      dummy_rp = copy.deepcopy(
          experiment.optimization_config.objective_thresholds  # pyre-ignore
      )
      multiplier = [0] * len(objective_orders)
      for ot in dummy_rp:
          # In the following, we find the index of the objective in
          # `objective_orders`. If there is an objective that does not exist
          # in `obs_data`, a ValueError is raised.
          try:
              objective_index = objective_orders.index(ot.metric.name)
          except ValueError:
              raise ValueError(
                  f"Metric {ot.metric.name} does not exist in `obs_data`."
              )
  
          if ot.op == ComparisonOp.LEQ:
              ot.bound = np.inf
              multiplier[objective_index] = -1
          else:
              ot.bound = -np.inf
              multiplier[objective_index] = 1
  
      # Finding the pareto frontier
      (
          frontier_observations,
          f,
          obj_w,
          _,
      ) = get_pareto_frontier_and_configs(
          modelbridge=mb_reference,
          observation_features=obs_feats,
          observation_data=obs_data,
          objective_thresholds=dummy_rp,
          use_model_predictions=False,
      )
  
      if len(frontier_observations) == 0:
          opt_config = cast(
              OptimizationConfig, mb_reference._optimization_config
          )
          outcome_constraints = opt_config._outcome_constraints
          if len(outcome_constraints) == 0:
              raise RuntimeError(
                  "No frontier observations found in the experiment and no constraints "
                  "are present. Please check the data of the experiment."
              )
  
          logger.warning(
              "No frontier observations found in the experiment. The likely cause is "
              "the absence of feasible arms in the experiment if a constraint is present."
              " Trying to find a reference point with the unconstrained objective values."
          )
  
          opt_config._outcome_constraints = (
              []
          )  # removing the constraints
          # getting the unconstrained pareto frontier
          (
              frontier_observations,
              f,
              obj_w,
              _,
          ) = get_pareto_frontier_and_configs(
              modelbridge=mb_reference,
              observation_features=obs_feats,
              observation_data=obs_data,
              objective_thresholds=dummy_rp,
              use_model_predictions=False,
          )
          opt_config._outcome_constraints = (
              outcome_constraints  # restoring constraints
          )
  
      # Need to reshuffle columns of `f` and `obj_w` to be consistent
      # with objective_orders.
      order = [
          objective_orders.index(metric_name)
          for metric_name in frontier_observations[0].data.metric_names
      ]
      f = f[:, order]
      obj_w = obj_w[order]
  
      # Dropping the columns related to outcome constraints.
      f = f[:, obj_w.nonzero().view(-1)]
      multiplier_tensor = torch.tensor(
          multiplier, dtype=f.dtype, device=f.device
      )
      multiplier_nonzero = multiplier_tensor[obj_w.nonzero().view(-1)]
  
      # Transforming all the objectives to be maximized.
      f_transformed = multiplier_nonzero * f
  
      # Finding nadir point.
      rp_raw = infer_reference_point(f_transformed)
  
      # Un-transforming the reference point.
      rp = multiplier_nonzero * rp_raw
  
      # Removing the non-objective metrics form the order.
      objective_orders_reduced = [
          x
          for (i, x) in enumerate(objective_orders)
          if multiplier[i] != 0
      ]
  
      # Constructing the objective thresholds.
      # NOTE: This assumes that objective_thresholds is already initialized.
      nadir_objective_thresholds = copy.deepcopy(
          experiment.optimization_config.objective_thresholds
      )
  
      for obj_threshold in nadir_objective_thresholds:
          obj_threshold.bound = rp[
              objective_orders_reduced.index(obj_threshold.metric.name)
          ].item()
  
      return nadir_objective_thresholds
  
imports: import copy
  from copy import deepcopy
  from itertools import combinations
  from logging import Logger
  from typing import cast, Dict, List, NamedTuple, Optional, Tuple, Union
  import numpy
  import torch
  from ax.core.batch_trial import BatchTrial
  from ax.core.data import Data
  from ax.core.experiment import Experiment
  from ax.core.metric import Metric
  from ax.core.objective import ScalarizedObjective
  from ax.core.observation import ObservationFeatures
  from ax.core.optimization_config import MultiObjectiveOptimizationConfig, OptimizationConfig
  from ax.core.outcome_constraint import ComparisonOp, ObjectiveThreshold, OutcomeConstraint
  from ax.core.search_space import RobustSearchSpace, SearchSpace
  from ax.core.types import TParameterization
  from ax.exceptions.core import AxError, UnsupportedError, UserInputError
  from ax.modelbridge.modelbridge_utils import _get_modelbridge_training_data, get_pareto_frontier_and_configs, observed_pareto_frontier
  from ax.modelbridge.registry import Models
  from ax.modelbridge.torch import TorchModelBridge
  from ax.modelbridge.transforms.search_space_to_float import SearchSpaceToFloat
  from ax.models.torch.posterior_mean import get_PosteriorMean
  from ax.models.torch_base import TorchModel
  from ax.utils.common.logger import get_logger
  from ax.utils.stats.statstools import relativize
  from botorch.utils.multi_objective import is_non_dominated
  from botorch.utils.multi_objective.hypervolume import infer_reference_point
label_desc: Use image node_id 11 for calling a global function with example usage: infer_reference_point_from_experiment(experiment) and returns: nadir_objective_thresholds