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: Args:
      datapoints: Either `None` or a `batch_shape x n x d` tensor of
          training features. If either `datapoints` or `comparisons` is
          `None`, construct a prior-only model.
      comparisons: Either `None` or a `batch_shape x m x 2` tensor of
          training comparisons; comparisons[i] is a noisy indicator
          suggesting the utility value of comparisons[i, 0]-th is greater
          than comparisons[i, 1]-th. If either `comparisons` or
          `datapoints` is `None`, construct a prior-only model.
      likelihood: A PairwiseLikelihood.
      covar_module: Covariance module.
      input_transform: An input transform that is applied in the model's
          forward pass.
      jitter: Value added to diagonal for numerical stability in
          `psd_safe_cholesky`.
      xtol: Stopping creteria in scipy.optimize.fsolve used to find f_map
          in `PairwiseGP._update`. If None, default behavior is handled by
          `PairwiseGP._update`.
      consolidate_rtol: `rtol` passed to `consolidate_duplicates`.
      consolidate_atol: `atol` passed to `consolidate_duplicates`.
      maxfev: The maximum number of calls to the function in
          scipy.optimize.fsolve. If None, default behavior is handled by
          `PairwiseGP._update`.
docstr_tok: ["Args",":","datapoints",":","Either","`","None","`","or","a","`","batch_shape","x","n","x","d","`","tensor","of","training","features",".","If","either","`","datapoints","`","or","`","comparisons","`","is","`","None","`",",","construct","a","prior-only","model",".","comparisons",":","Either","`","None","`","or","a","`","batch_shape","x","m","x","2","`","tensor","of","training","comparisons",";","comparisons","[","i","]","is","a","noisy","indicator","suggesting","the","utility","value","of","comparisons","[","i",",","0","]","-th","is","greater","than","comparisons","[","i",",","1","]","-th",".","If","either","`","comparisons","`","or","`","datapoints","`","is","`","None","`",",","construct","a","prior-only","model",".","likelihood",":","A","PairwiseLikelihood",".","covar_module",":","Covariance","module",".","input_transform",":","An","input","transform","that","is","applied","in","the","model's","forward","pass",".","jitter",":","Value","added","to","diagonal","for","numerical","stability","in","`","psd_safe_cholesky","`",".","xtol",":","Stopping","creteria","in","scipy.optimize.fsolve","used","to","find","f_map","in","`","PairwiseGP._update","`",".","If","None",",","default","behavior","is","handled","by","`","PairwiseGP._update","`",".","consolidate_rtol",":","`","rtol","`","passed","to","`","consolidate_duplicates","`",".","consolidate_atol",":","`","atol","`","passed","to","`","consolidate_duplicates","`",".","maxfev",":","The","maximum","number","of","calls","to","the","function","in","scipy.optimize.fsolve",".","If","None",",","default","behavior","is","handled","by","`","PairwiseGP._update","`","."]
code: def __init__(
      self,
      datapoints: Optional[Tensor],
      comparisons: Optional[Tensor],
      likelihood: Optional[PairwiseLikelihood] = None,
      covar_module: Optional[ScaleKernel] = None,
      input_transform: Optional[InputTransform] = None,
      *,
      jitter: float = 1e-6,
      xtol: Optional[float] = None,
      consolidate_rtol: float = 0.0,
      consolidate_atol: float = 1e-4,
      maxfev: Optional[int] = None,
  ) -> None:
      r"""
      Args:
          datapoints: Either `None` or a `batch_shape x n x d` tensor of
              training features. If either `datapoints` or `comparisons` is
              `None`, construct a prior-only model.
          comparisons: Either `None` or a `batch_shape x m x 2` tensor of
              training comparisons; comparisons[i] is a noisy indicator
              suggesting the utility value of comparisons[i, 0]-th is greater
              than comparisons[i, 1]-th. If either `comparisons` or
              `datapoints` is `None`, construct a prior-only model.
          likelihood: A PairwiseLikelihood.
          covar_module: Covariance module.
          input_transform: An input transform that is applied in the model's
              forward pass.
          jitter: Value added to diagonal for numerical stability in
              `psd_safe_cholesky`.
          xtol: Stopping creteria in scipy.optimize.fsolve used to find f_map
              in `PairwiseGP._update`. If None, default behavior is handled by
              `PairwiseGP._update`.
          consolidate_rtol: `rtol` passed to `consolidate_duplicates`.
          consolidate_atol: `atol` passed to `consolidate_duplicates`.
          maxfev: The maximum number of calls to the function in
              scipy.optimize.fsolve. If None, default behavior is handled by
              `PairwiseGP._update`.
      """
      super().__init__()
      # Input data validation
      if datapoints is not None and datapoints.dtype == torch.float32:
          warnings.warn(
              _get_single_precision_warning(str(datapoints.dtype)),
              category=InputDataWarning,
              stacklevel=2,
          )
  
      # Set optional parameters
      self._jitter = jitter
      self._xtol = xtol
      self._consolidate_rtol = consolidate_rtol
      self._consolidate_atol = consolidate_atol
      self._maxfev = maxfev
  
      if input_transform is not None:
          input_transform.to(datapoints)
          # input transformation is applied in set_train_data
          self.input_transform = input_transform
  
      # Compatibility variables with fit_gpytorch_*: Dummy likelihood
      # Likelihood is tightly tied with this model and
      # it doesn't make much sense to keep it separate
      self.likelihood = (
          PairwiseProbitLikelihood()
          if likelihood is None
          else likelihood
      )
  
      for key in self._buffer_names:
          self.register_buffer(key, None)
  
      self.train_inputs = []
      self.train_targets = None
      self.utility = None
  
      self.pred_cov_fac_need_update = True
      self.dim = None
      self.unconsolidated_datapoints = None
      self.unconsolidated_comparisons = None
      self.consolidated_datapoints = None
      self.consolidated_comparisons = None
      self.consolidated_indices = None
  
      # See set_train_data for additional compatibility variables.
      # Not that the datapoints here are not transformed even if input_transform
      # is not None to avoid double transformation during model fitting.
      # self.transform_inputs is called in `forward`
      self.set_train_data(datapoints, comparisons, update_model=False)
  
      # Set hyperparameters
      # Do not set the batch_shape explicitly so mean_module can operate in both mode
      # once fsolve used in _update can run in batch mode, we should explicitly set
      # the bacth shape here
      self.mean_module = ConstantMean()
      # Do not optimize constant mean prior
      for param in self.mean_module.parameters():
          param.requires_grad = False
  
      # set covariance module
      # the default outputscale here is only a rule of thumb, meant to keep
      # estimates away from scale value that would make Phi(f(x)) saturate
      # at 0 or 1
      if covar_module is None:
          os_lb, os_ub = 1e-2, 1e2
          ls_prior = GammaPrior(concentration=2.4, rate=2.7)
          ls_prior_mode = (ls_prior.concentration - 1) / ls_prior.rate
          covar_module = ScaleKernel(
              RBFKernel(
                  batch_shape=self.batch_shape,
                  ard_num_dims=self.dim,
                  lengthscale_prior=ls_prior,
                  lengthscale_constraint=GreaterThan(
                      lower_bound=1e-4,
                      transform=None,
                      initial_value=ls_prior_mode,
                  ),
                  dtype=torch.float64,
              ),
              outputscale_prior=SmoothedBoxPrior(a=os_lb, b=os_ub),
              # make sure we won't get extreme values for the output scale
              outputscale_constraint=Interval(
                  lower_bound=os_lb * 0.5,
                  upper_bound=os_ub * 2.0,
                  initial_value=1.0,
              ),
              dtype=torch.float64,
          )
      if not isinstance(covar_module, ScaleKernel):
          raise UnsupportedError(
              "PairwiseGP must be used with a ScaleKernel."
          )
      self.covar_module = covar_module
  
      self._x0 = None  # will store temporary results for warm-starting
      if self.datapoints is not None and self.comparisons is not None:
          self.to(
              dtype=self.datapoints.dtype, device=self.datapoints.device
          )
          # Find f_map for initial parameters with transformed datapoints
          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 1 to create a new PairwiseGP object from inherited base classes: Model, GP, FantasizeMixin with example: obj = PairwiseGP(datapoints, comparisons, likelihood, covar_module, input_transform)