code: def test_hypervolume(self, _, cuda: bool = False) -> None:
      for num_objectives in (2, 3):
          exp = get_branin_experiment_with_multi_objective(
              has_optimization_config=True,
              with_batch=True,
              num_objectives=num_objectives,
          )
          for trial in exp.trials.values():
              trial.mark_running(
                  no_runner_required=True
              ).mark_completed()
          # pyre-fixme[16]: Optional type has no attribute `metrics`.
          metrics_dict = exp.optimization_config.metrics
          # Objective thresholds and synthetic observations chosen to have closed-form
          # hypervolumes to test.
          objective_thresholds = [
              ObjectiveThreshold(
                  metric=metrics_dict["branin_a"],
                  bound=10.0,
                  relative=False,
                  op=ComparisonOp.LEQ,
              ),
              ObjectiveThreshold(
                  metric=metrics_dict["branin_b"],
                  bound=9.0,
                  relative=False,
                  op=ComparisonOp.LEQ,
              ),
          ]
          if num_objectives == 3:
              objective_thresholds.append(
                  ObjectiveThreshold(
                      metric=metrics_dict["branin_c"],
                      bound=8.0,
                      relative=False,
                      op=ComparisonOp.LEQ,
                  )
              )
          # pyre-fixme[16]: Optional type has no attribute `clone_with_args`.
          optimization_config = exp.optimization_config.clone_with_args(
              objective_thresholds=objective_thresholds
          )
          exp.attach_data(
              get_branin_data_multi_objective(
                  trial_indices=exp.trials.keys(),
                  num_objectives=num_objectives,
              )
          )
          modelbridge = TorchModelBridge(
              search_space=exp.search_space,
              model=MultiObjectiveBotorchModel(),
              optimization_config=optimization_config,
              transforms=[],
              experiment=exp,
              data=exp.fetch_data(),
              torch_device=torch.device("cuda" if cuda else "cpu"),
          )
          with patch(
              PARETO_FRONTIER_EVALUATOR_PATH,
              wraps=pareto_frontier_evaluator,
          ) as wrapped_frontier_evaluator:
              hv = observed_hypervolume(
                  modelbridge=modelbridge,
                  objective_thresholds=objective_thresholds,
              )
          expected_hv = 20 if num_objectives == 2 else 60  # 5 * 4 (* 3)
          wrapped_frontier_evaluator.assert_called_once()
          self.assertEqual(expected_hv, hv)
          if num_objectives == 3:
              # Test selected_metrics
              hv = observed_hypervolume(
                  modelbridge=modelbridge,
                  objective_thresholds=objective_thresholds,
                  selected_metrics=["branin_a", "branin_c"],
              )
              expected_hv = 15  # (5 - 0) * (5 - 2)
              self.assertEqual(expected_hv, hv)
              # test that non-objective outcome raises value error
              with self.assertRaises(ValueError):
                  hv = observed_hypervolume(
                      modelbridge=modelbridge,
                      objective_thresholds=objective_thresholds,
                      selected_metrics=["tracking"],
                  )
  
          with self.assertRaises(ValueError):
              predicted_hypervolume(
                  modelbridge=modelbridge,
                  objective_thresholds=objective_thresholds,
                  observation_features=[],
              )
  
          observation_features = [
              ObservationFeatures(parameters={"x1": 1.0, "x2": 2.0}),
              ObservationFeatures(parameters={"x1": 2.0, "x2": 1.0}),
          ]
          predicted_hv = predicted_hypervolume(
              modelbridge=modelbridge,
              objective_thresholds=objective_thresholds,
              observation_features=observation_features,
          )
          self.assertTrue(predicted_hv >= 0)
          if num_objectives == 3:
              # Test selected_metrics
              predicted_hv = predicted_hypervolume(
                  modelbridge=modelbridge,
                  objective_thresholds=objective_thresholds,
                  observation_features=observation_features,
                  selected_metrics=["branin_a", "branin_c"],
              )
              self.assertTrue(predicted_hv >= 0)
  
imports: from contextlib import ExitStack
  from typing import List, Optional
  from unittest.mock import patch
  import numpy
  import torch
  from ax.core.metric import Metric
  from ax.core.observation import ObservationData, ObservationFeatures
  from ax.core.optimization_config import MultiObjectiveOptimizationConfig
  from ax.core.outcome_constraint import ComparisonOp, ObjectiveThreshold, OutcomeConstraint
  from ax.core.parameter_constraint import ParameterConstraint
  from ax.exceptions.core import UnsupportedError
  from ax.modelbridge.factory import get_sobol
  from ax.modelbridge.modelbridge_utils import get_pareto_frontier_and_configs, observed_hypervolume, observed_pareto_frontier, pareto_frontier, predicted_hypervolume, predicted_pareto_frontier
  from ax.modelbridge.registry import Cont_X_trans, ST_MTGP_trans, Y_trans
  from ax.modelbridge.torch import TorchModelBridge
  from ax.models.torch.botorch_modular.model import BoTorchModel
  from ax.models.torch.botorch_moo import MultiObjectiveBotorchModel
  from ax.models.torch.botorch_moo_defaults import infer_objective_thresholds, pareto_frontier_evaluator
  from ax.service.utils.report_utils import exp_to_df
  from ax.utils.common.testutils import TestCase
  from ax.utils.common.typeutils import checked_cast, not_none
  from ax.utils.testing.core_stubs import get_branin_data_multi_objective, get_branin_experiment_with_multi_objective, get_hierarchical_search_space, get_hss_trials_with_fixed_parameter, get_non_monolithic_branin_moo_data, TEST_SOBOL_SEED
  from ax.utils.testing.mock import fast_botorch_optimize
  from ax.utils.testing.modeling_stubs import transform_1, transform_2
  from botorch.utils.multi_objective.pareto import is_non_dominated
label_desc: Use image node_id 4 for calling the MultiObjectiveTorchModelBridgeTest obj's underlying member method code with example usage: obj.test_hypervolume(_, cuda) without return types