docstr: Compute the box decomposition under each posterior sample.
  
  Args:
      num_new_points: The number of new points (beyond the points
          in X_baseline) that were used in the previous box decomposition.
          In the first box decomposition, this should be the number of points
          in X_baseline.
docstr_tok: ["Compute","the","box","decomposition","under","each","posterior","sample",".","Args",":","num_new_points",":","The","number","of","new","points","(","beyond","the","points","in","X_baseline",")","that","were","used","in","the","previous","box","decomposition",".","In","the","first","box","decomposition",",","this","should","be","the","number","of","points","in","X_baseline","."]
code: def _set_cell_bounds(self, num_new_points: int) -> None:
      r"""Compute the box decomposition under each posterior sample.
  
      Args:
          num_new_points: The number of new points (beyond the points
              in X_baseline) that were used in the previous box decomposition.
              In the first box decomposition, this should be the number of points
              in X_baseline.
      """
      if self.X_baseline.shape[0] > 0:
          with torch.no_grad():
              posterior = self.model.posterior(self.X_baseline)
          # Reset sampler, accounting for possible one-to-many transform.
          self.q_in = -1
          if self.base_sampler is None:
              # Initialize the base sampler if needed.
              samples = self.get_posterior_samples(posterior)
              self.base_sampler = deepcopy(self.sampler)
          else:
              samples = self.base_sampler(posterior)
          n_w = (
              posterior._extended_shape()[-2]
              // self.X_baseline.shape[-2]
          )
          self._set_sampler(
              q_in=num_new_points * n_w, posterior=posterior
          )
          # cache posterior
          if self._cache_root:
              # Note that this implicitly uses LinearOperator's caching to check if
              # the proper root decomposition has already been cached to
              # `posterior.mvn.lazy_covariance_matrix`, which it may have been in
              # the call to `self.base_sampler`, and computes it if not found
              self._baseline_L = self._compute_root_decomposition(
                  posterior=posterior
              )
          obj = self.objective(samples, X=self.X_baseline)
  
      else:
          sample_shape = (
              self.sampler.sample_shape
              if self.sampler is not None
              else self._default_sample_shape
          )
          obj = torch.empty(
              *sample_shape,
              0,
              self.ref_point.shape[-1],
              dtype=self.ref_point.dtype,
              device=self.ref_point.device,
          )
  
      # compute feasibility indicator if there are constraints
      if self.constraints is None or self.X_baseline.shape[0] == 0:
          feas = None
      else:
          feas = compute_feasibility_indicator(
              constraints=self.constraints, samples=samples
          )
  
      self._batch_sample_shape = obj.shape[:-2]
      # collapse batch dimensions
      # use numel() rather than view(-1) to handle case of no baseline points
      new_batch_shape = self._batch_sample_shape.numel()
      obj = obj.view(new_batch_shape, *obj.shape[-2:])
      if feas is not None:
          feas = feas.view(new_batch_shape, *feas.shape[-1:])
  
      if self.partitioning is None and not self.incremental_nehvi:
          self._compute_initial_hvs(obj=obj, feas=feas)
  
      if self.ref_point.shape[-1] > 2:
          # the partitioning algorithms run faster on the CPU
          # due to advanced indexing
          ref_point_cpu = self.ref_point.cpu()
          obj_cpu = obj.cpu()
          if feas is not None:
              feas_cpu = feas.cpu()
              obj_cpu = [
                  obj_cpu[i][feas_cpu[i]] for i in range(obj.shape[0])
              ]
          partitionings = []
          for sample in obj_cpu:
              partitioning = self.p_class(
                  ref_point=ref_point_cpu, Y=sample, **self.p_kwargs
              )
              partitionings.append(partitioning)
          self.partitioning = BoxDecompositionList(*partitionings)
      else:
          # use batched partitioning
          obj = _pad_batch_pareto_frontier(
              Y=obj,
              ref_point=self.ref_point.unsqueeze(0).expand(
                  obj.shape[0], self.ref_point.shape[-1]
              ),
              feasibility_mask=feas,
          )
          self.partitioning = self.p_class(
              ref_point=self.ref_point, Y=obj, **self.p_kwargs
          )
      cell_bounds = self.partitioning.get_hypercell_bounds().to(
          self.ref_point
      )
      cell_bounds = cell_bounds.view(
          2, *self._batch_sample_shape, *cell_bounds.shape[-2:]
      )  # 2 x batch_shape x sample_shape x num_cells x m
      self.register_buffer("cell_lower_bounds", cell_bounds[0])
      self.register_buffer("cell_upper_bounds", cell_bounds[1])
  
imports: from __future__ import annotations
  import warnings
  from copy import deepcopy
  from itertools import combinations
  from typing import Callable, List, Optional, Union
  import torch
  from botorch.acquisition.cached_cholesky import CachedCholeskyMCSamplerMixin
  from botorch.acquisition.multi_objective.objective import MCMultiOutputObjective
  from botorch.acquisition.multi_objective.utils import prune_inferior_points_multi_objective
  from botorch.exceptions.errors import BotorchError, BotorchTensorDimensionError, UnsupportedError
  from botorch.exceptions.warnings import BotorchWarning
  from botorch.models.model import Model
  from botorch.sampling.base import MCSampler
  from botorch.utils.multi_objective.box_decompositions.box_decomposition_list import BoxDecompositionList
  from botorch.utils.multi_objective.box_decompositions.dominated import DominatedPartitioning
  from botorch.utils.multi_objective.box_decompositions.non_dominated import FastNondominatedPartitioning, NondominatedPartitioning
  from botorch.utils.multi_objective.box_decompositions.utils import _pad_batch_pareto_frontier
  from botorch.utils.objective import compute_feasibility_indicator
  from botorch.utils.torch import BufferDict
  from torch import Tensor
label_desc: Use image node_id 4 for calling the NoisyExpectedHypervolumeMixin obj's underlying member method code with example usage: obj._set_cell_bounds(num_new_points) without return types