class_docstr: Constrained max posterior sampling.
  
  Posterior sampling where we try to maximize an objective function while
  simulatenously satisfying a set of constraints c1(x) <= 0, c2(x) <= 0,
  ..., cm(x) <= 0 where c1, c2, ..., cm are black-box constraint functions.
  Each constraint function is modeled by a seperate GP model. We follow the
  procedure as described in https://doi.org/10.48550/arxiv.2002.08526.
  
  Example:
      >>> CMPS = ConstrainedMaxPosteriorSampling(
              model,
              constraint_model=ModelListGP(cmodel1, cmodel2),
          )
      >>> X = torch.rand(2, 100, 3)
      >>> sampled_X = CMPS(X, num_samples=5)
docstr: Sample from the model posterior.
  
  Args:
      X: A `batch_shape x N x d`-dim Tensor from which to sample (in the `N`
          dimension) according to the maximum posterior value under the objective.
      num_samples: The number of samples to draw.
      observation_noise: If True, sample with observation noise.
  
  Returns:
      A `batch_shape x num_samples x d`-dim Tensor of samples from `X`, where
          `X[..., i, :]` is the `i`-th sample.
docstr_tok: ["Sample","from","the","model","posterior",".","Args",":","X",":","A","`","batch_shape","x","N","x","d","`","-dim","Tensor","from","which","to","sample","(","in","the","`","N","`","dimension",")","according","to","the","maximum","posterior","value","under","the","objective",".","num_samples",":","The","number","of","samples","to","draw",".","observation_noise",":","If","True",",","sample","with","observation","noise",".","Returns",":","A","`","batch_shape","x","num_samples","x","d","`","-dim","Tensor","of","samples","from","`","X","`",",","where","`","X","[","...",",","i",",",":","]","`","is","the","`","i","`","-th","sample","."]
code: def forward(
      self,
      X: Tensor,
      num_samples: int = 1,
      observation_noise: bool = False,
  ) -> Tensor:
      r"""Sample from the model posterior.
  
      Args:
          X: A `batch_shape x N x d`-dim Tensor from which to sample (in the `N`
              dimension) according to the maximum posterior value under the objective.
          num_samples: The number of samples to draw.
          observation_noise: If True, sample with observation noise.
  
      Returns:
          A `batch_shape x num_samples x d`-dim Tensor of samples from `X`, where
              `X[..., i, :]` is the `i`-th sample.
      """
      posterior = self.model.posterior(
          X=X,
          observation_noise=observation_noise,
          # Note: `posterior_transform` is only used for the objective
          posterior_transform=self.posterior_transform,
      )
      Y_samples = posterior.rsample(
          sample_shape=torch.Size([num_samples])
      )
  
      c_posterior = self.constraint_model.posterior(
          X=X, observation_noise=observation_noise
      )
      C_samples = c_posterior.rsample(
          sample_shape=torch.Size([num_samples])
      )
  
      # Convert the objective and constraint samples into a scalar-valued "score"
      scores = self._convert_samples_to_scores(
          Y_samples=Y_samples, C_samples=C_samples
      )
      return self.maximize_samples(
          X=X, samples=scores, num_samples=num_samples
      )
  
imports: from __future__ import annotations
  from abc import ABC, abstractmethod
  from typing import Any, Optional, Union
  import torch
  from botorch.acquisition.acquisition import AcquisitionFunction
  from botorch.acquisition.objective import IdentityMCObjective, MCAcquisitionObjective, PosteriorTransform
  from botorch.generation.utils import _flip_sub_unique
  from botorch.models.model import Model
  from botorch.models.model_list_gp_regression import ModelListGP
  from botorch.models.multitask import MultiTaskGP
  from botorch.utils.sampling import batched_multinomial
  from botorch.utils.transforms import standardize
  from torch import Tensor
  from torch.nn import Module
label_desc: Use image node_id 3 for calling the ConstrainedMaxPosteriorSampling obj's underlying member method code with example usage: obj.forward(X, num_samples, observation_noise) and returns: self