class_docstr: Probit GP for preference learning with Laplace approximation
  
  A probit-likelihood GP that learns via pairwise comparison data, using a
  Laplace approximation of the posterior of the estimated utility values. By
  default it uses a scaled RBF kernel.
  
  Implementation is based on [Chu2005preference]_.
  Also see [Brochu2010tutorial]_ for additional reference.
  
  Note that in [Chu2005preference]_ the likelihood of a pairwise comparison
  is :math:`\left(\frac{f(x_1) - f(x_2)}{\sqrt{2}\sigma}\right)`, i.e. a scale is
  used in the denominator. To maintain consistency with usage of kernels
  elsewhere in BoTorch, we instead do not include :math:`\sigma` in the code
  (implicitly setting it to 1) and use ScaleKernel to scale the function.
  
  In the example below, the user/decision maker has stated that they prefer
  the first item over the second item and the third item over the second item,
  generating comparisons [0, 1] and [2, 1].
  Example:
      >>> from botorch.models import PairwiseGP
      >>> import torch
      >>> datapoints = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
      >>> comparisons = torch.Tensor([[0, 1], [2, 1]])
      >>> model = PairwiseGP(datapoints, comparisons)
class_docstr_tok: ["Probit","GP","for","preference","learning","with","Laplace","approximation","A","probit-likelihood","GP","that","learns","via","pairwise","comparison","data",",","using","a","Laplace","approximation","of","the","posterior","of","the","estimated","utility","values",".","By","default","it","uses","a","scaled","RBF","kernel",".","Implementation","is","based","on","[","Chu2005preference","]","_",".","Also","see","[","Brochu2010tutorial","]","_","for","additional","reference",".","Note","that","in","[","Chu2005preference","]","_","the","likelihood","of","a","pairwise","comparison","is",":","math",":","`","\\left","(","\\frac","{","f","(","x_1",")","-","f","(","x_2",")","}","{","\\sqrt","{","2","}","\\sigma","}","\\right",")","`",",","i.e",".","a","scale","is","used","in","the","denominator",".","To","maintain","consistency","with","usage","of","kernels","elsewhere","in","BoTorch",",","we","instead","do","not","include",":","math",":","`","\\sigma","`","in","the","code","(","implicitly","setting","it","to","1",")","and","use","ScaleKernel","to","scale","the","function",".","In","the","example","below",",","the","user\/decision","maker","has","stated","that","they","prefer","the","first","item","over","the","second","item","and","the","third","item","over","the","second","item",",","generating","comparisons","[","0",",","1","]","and","[","2",",","1","]",".","Example",":",">",">",">","from","botorch.models","import","PairwiseGP",">",">",">","import","torch",">",">",">","datapoints","=","torch.Tensor","(","[","[","1",",","2",",","3","]",",","[","4",",","5",",","6","]",",","[","7",",","8",",","9","]","]",")",">",">",">","comparisons","=","torch.Tensor","(","[","[","0",",","1","]",",","[","2",",","1","]","]",")",">",">",">","model","=","PairwiseGP","(","datapoints",",","comparisons",")"]
docstr: Set datapoints and comparisons and update model properties if needed
  
  Args:
      datapoints: Either `None` or a `batch_shape x n x d` dimension
          tensor X. If there are input transformations, assume the
          datapoints are not transformed. If either `datapoints` or
          `comparisons` is `None`, construct a prior-only model.
      comparisons: Either `None` or a tensor of size `batch_shape x m x
          2`. (i, j) means f_i is preferred over f_j. If either
          `comparisons` or `datapoints` is `None`, construct a prior-only
          model.
      strict: `strict` argument as in gpytorch.models.exact_gp for compatibility
          when using fit_gpytorch_model with input_transform.
      update_model: True if we want to refit the model (see _update) after
          re-setting the data.
docstr_tok: ["Set","datapoints","and","comparisons","and","update","model","properties","if","needed","Args",":","datapoints",":","Either","`","None","`","or","a","`","batch_shape","x","n","x","d","`","dimension","tensor","X",".","If","there","are","input","transformations",",","assume","the","datapoints","are","not","transformed",".","If","either","`","datapoints","`","or","`","comparisons","`","is","`","None","`",",","construct","a","prior-only","model",".","comparisons",":","Either","`","None","`","or","a","tensor","of","size","`","batch_shape","x","m","x","2","`",".","(","i",",","j",")","means","f_i","is","preferred","over","f_j",".","If","either","`","comparisons","`","or","`","datapoints","`","is","`","None","`",",","construct","a","prior-only","model",".","strict",":","`","strict","`","argument","as","in","gpytorch.models.exact_gp","for","compatibility","when","using","fit_gpytorch_model","with","input_transform",".","update_model",":","True","if","we","want","to","refit","the","model","(","see","_update",")","after","re-setting","the","data","."]
code: def set_train_data(
      self,
      datapoints: Optional[Tensor] = None,
      comparisons: Optional[Tensor] = None,
      strict: bool = False,
      update_model: bool = True,
  ) -> None:
      r"""Set datapoints and comparisons and update model properties if needed
  
      Args:
          datapoints: Either `None` or a `batch_shape x n x d` dimension
              tensor X. If there are input transformations, assume the
              datapoints are not transformed. If either `datapoints` or
              `comparisons` is `None`, construct a prior-only model.
          comparisons: Either `None` or a tensor of size `batch_shape x m x
              2`. (i, j) means f_i is preferred over f_j. If either
              `comparisons` or `datapoints` is `None`, construct a prior-only
              model.
          strict: `strict` argument as in gpytorch.models.exact_gp for compatibility
              when using fit_gpytorch_model with input_transform.
          update_model: True if we want to refit the model (see _update) after
              re-setting the data.
      """
      # When datapoints and/or comparisons are None, we are constructing
      # a prior-only model
      if datapoints is None or comparisons is None:
          return
  
      # following gpytorch.models.exact_gp.set_train_data
      if datapoints is not None:
          if torch.is_tensor(datapoints):
              inputs = [datapoints]
  
          inputs = tuple(
              input_.unsqueeze(-1)
              if input_.ndimension() == 1
              else input_
              for input_ in inputs
          )
          if strict:
              _check_strict_input(inputs, self.train_inputs, "inputs")
  
          datapoints = inputs[0]
          # Compatibility variables with fit_gpytorch_*
          # alias for datapoints ("train_inputs")
          self.train_inputs = inputs
  
      if comparisons is not None:
          if strict:
              _check_strict_input(
                  [comparisons], [self.train_targets], "targets"
              )
  
          # convert to long so that it can be used as index and
          # compatible with Tensor.scatter_
          comparisons = comparisons.long()
          # Compatibility variables with fit_gpytorch_*
          # alias for comparisons ("train_targets" here)
          self.train_targets = comparisons
  
      # self.datapoints and self.comparisons are being updated here
      self._consolidate_duplicates(datapoints, comparisons)
  
      # Compatibility variables with optimize_acqf
      self._dtype = self.datapoints.dtype
      self._num_outputs = 1  # 1 latent value output per observation
  
      self.dim = self.datapoints.shape[-1]  # feature dimensions
      self.n = self.datapoints.shape[-2]  # num datapoints
      self.m = self.comparisons.shape[-2]  # num pairwise comparisons
      # D is batch_size x m x n or num_comparison x num_datapoints.
      # D_k_i is the s_k(x_i) value as in equation (6) in [Chu2005preference]_
      # D will usually be very sparse as well
      # TODO swap out scatter_ so that comparisons could be int instead of long
      # TODO: make D a sparse matrix once pytorch has better support for
      #       sparse tensors
      D_size = torch.Size((*(self.batch_shape), self.m, self.n))
      self.D = torch.zeros(
          D_size,
          dtype=self.datapoints.dtype,
          device=self.datapoints.device,
      )
      comp_view = self.comparisons.view(-1, self.m, 2).long()
      for i, sub_D in enumerate(self.D.view(-1, self.m, self.n)):
          sub_D.scatter_(1, comp_view[i, :, [0]], 1)
          sub_D.scatter_(1, comp_view[i, :, [1]], -1)
      self.DT = self.D.transpose(-1, -2)
  
      if update_model:
          transformed_dp = self.transform_inputs(self.datapoints)
          self._update(transformed_dp)
  
      self.to(self.datapoints)
  
imports: from __future__ import annotations
  import warnings
  from copy import deepcopy
  from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
  import numpy
  import torch
  from botorch.acquisition.objective import PosteriorTransform
  from botorch.exceptions import UnsupportedError
  from botorch.exceptions.warnings import _get_single_precision_warning, InputDataWarning
  from botorch.models.likelihoods.pairwise import PairwiseLikelihood, PairwiseProbitLikelihood
  from botorch.models.model import FantasizeMixin, Model
  from botorch.models.transforms.input import InputTransform
  from botorch.models.utils.assorted import consolidate_duplicates
  from botorch.posteriors.gpytorch import GPyTorchPosterior
  from botorch.posteriors.posterior import Posterior
  from gpytorch import settings
  from gpytorch.constraints import GreaterThan, Interval
  from gpytorch.distributions.multivariate_normal import MultivariateNormal
  from gpytorch.kernels.rbf_kernel import RBFKernel
  from gpytorch.kernels.scale_kernel import ScaleKernel
  from gpytorch.means.constant_mean import ConstantMean
  from gpytorch.mlls import MarginalLogLikelihood
  from gpytorch.models.gp import GP
  from gpytorch.priors.smoothed_box_prior import SmoothedBoxPrior
  from gpytorch.priors.torch_priors import GammaPrior
  from linear_operator.operators import LinearOperator, RootLinearOperator
  from linear_operator.utils.cholesky import psd_safe_cholesky
  from linear_operator.utils.errors import NotPSDError
  from scipy import optimize
  from torch import float32, float64, Tensor
  from torch.nn.modules.module import _IncompatibleKeys
label_desc: Use image node_id 20 for calling the PairwiseGP obj's underlying member method code with example usage: obj.set_train_data(datapoints, comparisons, strict, update_model) without return types