class_docstr: Abstract class for Pairwise MC Sampler.
  
  This sampler will sample pairwise comparisons. It is to be used together
  with PairwiseGP and BoTorch acquisition functions (e.g., qKnowledgeGradient)
class_docstr_tok: ["Abstract","class","for","Pairwise","MC","Sampler",".","This","sampler","will","sample","pairwise","comparisons",".","It","is","to","be","used","together","with","PairwiseGP","and","BoTorch","acquisition","functions","(","e.g.",",","qKnowledgeGradient",")"]
docstr: Draws MC samples from the posterior and make comparisons
  
  Args:
      posterior: The Posterior to sample from.
          The returned samples are expected to have output dimension of 1.
  
  Returns:
      Posterior sample pairwise comparisons.
docstr_tok: ["Draws","MC","samples","from","the","posterior","and","make","comparisons","Args",":","posterior",":","The","Posterior","to","sample","from",".","The","returned","samples","are","expected","to","have","output","dimension","of","1",".","Returns",":","Posterior","sample","pairwise","comparisons","."]
code: def forward(self, posterior: Posterior) -> Tensor:
      r"""Draws MC samples from the posterior and make comparisons
  
      Args:
          posterior: The Posterior to sample from.
              The returned samples are expected to have output dimension of 1.
  
      Returns:
          Posterior sample pairwise comparisons.
      """
      samples = super().forward(posterior)
      np.random.seed(self.seed)
  
      s_n = samples.shape[-2]  # candidate number per batch
      if s_n < 2:
          raise RuntimeError(
              "Number of samples < 2, cannot make comparisons"
          )
  
      # TODO: Don't instantiate a generator
      all_pairs = np.array(list(combinations(range(s_n), 2)))
      if self.max_num_comparisons is None:
          comp_n = len(all_pairs)
      else:
          comp_n = min(self.max_num_comparisons, len(all_pairs))
  
      comp_pairs = all_pairs[
          np.random.choice(range(len(all_pairs)), comp_n, replace=False)
      ]
      s_comps_size = torch.Size((*samples.shape[:-2], comp_n, 2))
      s_v = samples.view(-1, s_n)
  
      idx1, idx2 = comp_pairs[:, 0], comp_pairs[:, 1]
      prefs = (s_v[:, idx1] > s_v[:, idx2]).long().cpu()
      cpt = comp_pairs.T
      c1 = np.choose(prefs, cpt)
      c2 = np.choose(1 - prefs, cpt)
      s_comps = torch.stack([c1, c2], dim=-1).reshape(s_comps_size)
  
      return s_comps
  
imports: from __future__ import annotations
  from itertools import combinations
  from typing import Any, Optional
  import numpy
  import torch
  from botorch.posteriors.posterior import Posterior
  from botorch.sampling.base import MCSampler
  from botorch.sampling.normal import IIDNormalSampler, SobolQMCNormalSampler
  from torch import Tensor
label_desc: Use image node_id 2 for calling the PairwiseMCSampler obj's underlying member method code with example usage: obj.forward(posterior) and returns: s_comps