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: Convert the objective and constraint samples into a score.
  
  The logic is as follows:
      - If a realization has at least one feasible candidate we use the objective
          value as the score and set all infeasible candidates to -inf.
      - If a realization doesn't have a feasible candidate we set the score to
          the negative total violation of the constraints to incentivize choosing
          the candidate with the smallest constraint violation.
  
  Args:
      Y_samples: A `num_samples x batch_shape x num_cand x 1`-dim Tensor of
          samples from the objective function.
      C_samples: A `num_samples x batch_shape x num_cand x num_constraints`-dim
          Tensor of samples from the constraints.
  
  Returns:
      A `num_samples x batch_shape x num_cand x 1`-dim Tensor of scores.
docstr_tok: ["Convert","the","objective","and","constraint","samples","into","a","score",".","The","logic","is","as","follows",":","-","If","a","realization","has","at","least","one","feasible","candidate","we","use","the","objective","value","as","the","score","and","set","all","infeasible","candidates","to","-inf",".","-","If","a","realization","does","n't","have","a","feasible","candidate","we","set","the","score","to","the","negative","total","violation","of","the","constraints","to","incentivize","choosing","the","candidate","with","the","smallest","constraint","violation",".","Args",":","Y_samples",":","A","`","num_samples","x","batch_shape","x","num_cand","x","1","`","-dim","Tensor","of","samples","from","the","objective","function",".","C_samples",":","A","`","num_samples","x","batch_shape","x","num_cand","x","num_constraints","`","-dim","Tensor","of","samples","from","the","constraints",".","Returns",":","A","`","num_samples","x","batch_shape","x","num_cand","x","1","`","-dim","Tensor","of","scores","."]
code: def _convert_samples_to_scores(self, Y_samples, C_samples) -> Tensor:
      r"""Convert the objective and constraint samples into a score.
  
      The logic is as follows:
          - If a realization has at least one feasible candidate we use the objective
              value as the score and set all infeasible candidates to -inf.
          - If a realization doesn't have a feasible candidate we set the score to
              the negative total violation of the constraints to incentivize choosing
              the candidate with the smallest constraint violation.
  
      Args:
          Y_samples: A `num_samples x batch_shape x num_cand x 1`-dim Tensor of
              samples from the objective function.
          C_samples: A `num_samples x batch_shape x num_cand x num_constraints`-dim
              Tensor of samples from the constraints.
  
      Returns:
          A `num_samples x batch_shape x num_cand x 1`-dim Tensor of scores.
      """
      is_feasible = (C_samples <= 0).all(
          dim=-1
      )  # num_samples x batch_shape x num_cand
      has_feasible_candidate = is_feasible.any(dim=-1)
  
      scores = Y_samples.clone()
      scores[~is_feasible] = -float("inf")
      if not has_feasible_candidate.all():
          # Use negative total violation for samples where no candidate is feasible
          total_violation = (
              C_samples[~has_feasible_candidate]
              .clamp(min=0)
              .sum(dim=-1, keepdim=True)
          )
          scores[~has_feasible_candidate] = -total_violation
      return scores
  
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 2 for calling the ConstrainedMaxPosteriorSampling obj's underlying member method code with example usage: obj._convert_samples_to_scores(Y_samples, C_samples) and returns: scores