code: def test_mc_acquisition_function_with_constraints(self):
      for dtype in (torch.float, torch.double):
          with self.subTest(dtype=dtype):
              num_samples, n, q, d, m = 5, 4, 1, 3, 1
              X = torch.randn(n, q, d, device=self.device, dtype=dtype)
              samples = torch.randn(
                  num_samples, n, q, m, device=self.device, dtype=dtype
              )
              mm = MockModel(MockPosterior(samples=samples))
              nei_args = {
                  "model": mm,
                  "X_baseline": X,
                  "prune_baseline": False,
              }
              for acqf_constructor in [
                  partial(
                      qProbabilityOfImprovement, model=mm, best_f=0.0
                  ),
                  partial(qExpectedImprovement, model=mm, best_f=0.0),
                  # cache_root=True not supported by MockModel, see test_cache_root
                  partial(
                      qNoisyExpectedImprovement,
                      cache_root=False,
                      **nei_args,
                  ),
                  partial(
                      qNoisyExpectedImprovement,
                      cache_root=True,
                      **nei_args,
                  ),
              ]:
                  acqf = acqf_constructor()
                  mm._posterior._samples = (
                      torch.cat((samples, samples), dim=-2)
                      if isinstance(acqf, qNoisyExpectedImprovement)
                      else samples
                  )
                  with self.subTest(acqf_class=type(acqf)):
                      for con in [feasible_con, infeasible_con]:
                          cacqf = acqf_constructor(constraints=[con])
                          # for NEI test
                          target = "botorch.acquisition.utils.get_infeasible_cost"
                          inf_cost = torch.tensor(
                              3, device=self.device, dtype=dtype
                          )
                          with mock.patch(
                              target, return_value=inf_cost
                          ):
                              vals = cacqf(X)
                          # NOTE: this is only true for q = 1
                          expected_vals = (
                              acqf(X) * (con(samples) < 0).squeeze()
                          )
                          self.assertAllClose(vals, expected_vals)
  
                      with self.assertRaisesRegex(
                          ValueError,
                          "ConstrainedMCObjective as well as constraints passed",
                      ):
                          acqf_constructor(
                              constraints=[feasible_con],
                              objective=ConstrainedMCObjective(
                                  objective=IdentityMCObjective,
                                  constraints=[feasible_con],
                              ),
                          )
              # Forcing negative samples, which will throw an error with simple
              # regret because the acquisition utility is negative.
              samples = -torch.rand(
                  n, q, m, device=self.device, dtype=dtype
              )
              mm = MockModel(MockPosterior(samples=samples))
              cacqf = NegativeReducingMCAcquisitionFunction(
                  model=mm, constraints=[feasible_con]
              )
              with self.assertRaisesRegex(
                  ValueError,
                  "Constraint-weighting requires unconstrained "
                  "acquisition values to be non-negative",
              ):
                  cacqf(X)
  
              # Test highlighting both common and different behavior of the old
              # `ConstrainedMCObjective` and new `constraints` implementation.
              # 1. Highlighting difference:
              q = 1
              samples = torch.randn(
                  n, q, m, device=self.device, dtype=dtype
              )
              mm = MockModel(MockPosterior(samples=samples))
              constrained_objective = ConstrainedMCObjective(
                  objective=IdentityMCObjective(),
                  constraints=[infeasible_con],
                  infeasible_cost=0.0,
              )
              # The old `ConstrainedMCObjective`-based implementation does not scale
              # the best_f value by the feasibility indicator, while the new
              # `constraints`-based implementation does. Therefore, the old version
              # yields an acquisition value of 1, even though the constraint is not
              # satisfied.
              best_f = -1.0
              old_acqf = qExpectedImprovement(
                  model=mm,
                  best_f=best_f,
                  objective=constrained_objective,
              )
              new_acqf = qExpectedImprovement(
                  model=mm, best_f=best_f, constraints=[infeasible_con]
              )
              old_val = old_acqf(X)
              self.assertAllClose(old_val, torch.ones_like(old_val))
              new_val = new_acqf(X)
              self.assertAllClose(new_val, torch.zeros_like(new_val))
  
              # 2. Highlighting commonality:
              # When best_f = 0 and infeasible_cost = 0, both implementations yield
              # the same results.
              constrained_objective = ConstrainedMCObjective(
                  objective=IdentityMCObjective(),
                  constraints=[feasible_con],
                  infeasible_cost=0.0,
              )
              best_f = 0.0
              old_acqf = qExpectedImprovement(
                  model=mm,
                  best_f=best_f,
                  objective=constrained_objective,
              )
              new_acqf = qExpectedImprovement(
                  model=mm, best_f=best_f, constraints=[feasible_con]
              )
              old_val = old_acqf(X)
              new_val = new_acqf(X)
              self.assertAllClose(new_val, old_val)
  
imports: import warnings
  from copy import deepcopy
  from functools import partial
  from itertools import product
  from math import pi
  from unittest import mock
  import torch
  from botorch import settings
  from botorch.acquisition.monte_carlo import MCAcquisitionFunction, qExpectedImprovement, qNoisyExpectedImprovement, qProbabilityOfImprovement, qSimpleRegret, qUpperConfidenceBound, SampleReducingMCAcquisitionFunction
  from botorch.acquisition.objective import ConstrainedMCObjective, GenericMCObjective, IdentityMCObjective, ScalarizedPosteriorTransform
  from botorch.acquisition.utils import prune_inferior_points
  from botorch.exceptions import BotorchWarning, UnsupportedError
  from botorch.models import SingleTaskGP
  from botorch.sampling.normal import IIDNormalSampler, SobolQMCNormalSampler
  from botorch.utils.low_rank import sample_cached_cholesky
  from botorch.utils.test_helpers import DummyNonScalarizingPosteriorTransform
  from botorch.utils.testing import BotorchTestCase, MockModel, MockPosterior
  from botorch.utils.transforms import standardize
  from torch import Tensor
label_desc: Use image node_id 1 for calling the TestMCAcquisitionFunctionWithConstraints obj's underlying member method code with example usage: obj.test_mc_acquisition_function_with_constraints() without return types