code: def compute_posterior_pareto_frontier(
      experiment: Experiment,
      primary_objective: Metric,
      secondary_objective: Metric,
      data: Optional[Data] = None,
      outcome_constraints: Optional[List[OutcomeConstraint]] = None,
      absolute_metrics: Optional[List[str]] = None,
      num_points: int = 10,
      trial_index: Optional[int] = None,
      chebyshev: bool = True,
  ) -> ParetoFrontierResults:
      """Compute the Pareto frontier between two objectives. For experiments
      with batch trials, a trial index or data object must be provided.
  
      This is done by fitting a GP and finding the pareto front according to the
      GP posterior mean.
  
      Args:
          experiment: The experiment to compute a pareto frontier for.
          primary_objective: The primary objective to optimize.
          secondary_objective: The secondary objective against which
              to trade off the primary objective.
          outcome_constraints: Outcome
              constraints to be respected by the optimization. Can only contain
              constraints on metrics that are not primary or secondary objectives.
          absolute_metrics: List of outcome metrics that
              should NOT be relativized w.r.t. the status quo (all other outcomes
              will be in % relative to status_quo).
          num_points: The number of points to compute on the
              Pareto frontier.
          chebyshev: Whether to use augmented_chebyshev_scalarization
              when computing Pareto Frontier points.
  
      Returns:
          ParetoFrontierResults: A NamedTuple with fields listed in its definition.
      """
      model_gen_options = {
          "acquisition_function_kwargs": {
              "chebyshev_scalarization": chebyshev
          }
      }
  
      if (
          trial_index is None
          and data is None
          and any(
              isinstance(t, BatchTrial)
              for t in experiment.trials.values()
          )
      ):
          raise UnsupportedError(
              "Must specify trial index or data for experiment with batch trials"
          )
      absolute_metrics = (
          [] if absolute_metrics is None else absolute_metrics
      )
      for metric in absolute_metrics:
          if metric not in experiment.metrics:
              raise ValueError(
                  f"Model was not fit on metric `{metric}`"
              )
  
      if outcome_constraints is None:
          outcome_constraints = []
      else:
          # ensure we don't constrain an objective
          _validate_outcome_constraints(
              outcome_constraints=outcome_constraints,
              primary_objective=primary_objective,
              secondary_objective=secondary_objective,
          )
  
      # build posterior mean model
      if not data:
          try:
              data = (
                  experiment.trials[trial_index].fetch_data()
                  if trial_index
                  else experiment.fetch_data()
              )
          except Exception as e:
              logger.info(
                  f"Could not fetch data from experiment or trial: {e}"
              )
  
      # The weights here are just dummy weights that we pass in to construct the
      # modelbridge. We set the weight to -1 if `lower_is_better` is `True` and
      # 1 otherwise. This code would benefit from a serious revamp.
      oc = _build_new_optimization_config(
          weights=np.array(
              [
                  -1 if primary_objective.lower_is_better else 1,
                  -1 if secondary_objective.lower_is_better else 1,
              ]
          ),
          primary_objective=primary_objective,
          secondary_objective=secondary_objective,
          outcome_constraints=outcome_constraints,
      )
      model = Models.MOO(
          experiment=experiment,
          data=data,
          acqf_constructor=get_PosteriorMean,
          optimization_config=oc,
      )
  
      status_quo = experiment.status_quo
      if status_quo:
          try:
              status_quo_prediction = model.predict(
                  [
                      ObservationFeatures(
                          parameters=status_quo.parameters,
                          trial_index=trial_index,
                      )
                  ]
              )
          except ValueError as e:
              logger.warning(
                  f"Could not predict OOD status_quo outcomes: {e}"
              )
              status_quo = None
              status_quo_prediction = None
      else:
          status_quo_prediction = None
  
      param_dicts: List[TParameterization] = []
  
      # Construct weightings with linear angular spacing.
      # TODO: Verify whether 0, 1 weights cause problems because of subset_model.
      alpha = np.linspace(0 + 0.01, np.pi / 2 - 0.01, num_points)
      primary_weight = (
          -1 if primary_objective.lower_is_better else 1
      ) * np.cos(alpha)
      secondary_weight = (
          -1 if secondary_objective.lower_is_better else 1
      ) * np.sin(alpha)
      weights_list = np.stack(
          [primary_weight, secondary_weight]
      ).transpose()
      for weights in weights_list:
          outcome_constraints = outcome_constraints
          oc = _build_new_optimization_config(
              weights=weights,
              primary_objective=primary_objective,
              secondary_objective=secondary_objective,
              outcome_constraints=outcome_constraints,
          )
          # TODO: (jej) T64002590 Let this serve as a starting point for optimization.
          # ex. Add global spacing criterion. Implement on BoTorch side.
          # pyre-fixme [6]: Expected different type for model_gen_options
          run = model.gen(
              1,
              model_gen_options=model_gen_options,
              optimization_config=oc,
          )
          param_dicts.append(run.arms[0].parameters)
  
      # Call predict on points to get their decomposed metrics.
      means, cov = model.predict(
          [
              ObservationFeatures(parameters)
              for parameters in param_dicts
          ]
      )
  
      return _extract_pareto_frontier_results(
          param_dicts=param_dicts,
          means=means,
          variances=cov,
          primary_metric=primary_objective.name,
          secondary_metric=secondary_objective.name,
          absolute_metrics=absolute_metrics,
          outcome_constraints=outcome_constraints,
          status_quo_prediction=status_quo_prediction,
      )
  
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 7 for calling a global function with example usage: compute_posterior_pareto_frontier(experiment, primary_objective, secondary_objective, data, outcome_constraints, absolute_metrics, num_points, trial_index, chebyshev) and returns: _extract_pareto_frontier_results