class_docstr: Base class for batched multi-output GPyTorch models with independent outputs.
  
  This model should be used when the same training data is used for all outputs.
  Outputs are modeled independently by using a different batch for each output.
  
  :meta private:
class_docstr_tok: ["Base","class","for","batched","multi-output","GPyTorch","models","with","independent","outputs",".","This","model","should","be","used","when","the","same","training","data","is","used","for","all","outputs",".","Outputs","are","modeled","independently","by","using","a","different","batch","for","each","output",".",":","meta","private",":"]
docstr: Condition the model on new observations.
  
  Args:
      X: A `batch_shape x n' x d`-dim Tensor, where `d` is the dimension of
          the feature space, `m` is the number of points per batch, and
          `batch_shape` is the batch shape (must be compatible with the
          batch shape of the model).
      Y: A `batch_shape' x n' x m`-dim Tensor, where `m` is the number of
          model outputs, `n'` is the number of points per batch, and
          `batch_shape'` is the batch shape of the observations.
          `batch_shape'` must be broadcastable to `batch_shape` using
          standard broadcasting semantics. If `Y` has fewer batch dimensions
          than `X`, its is assumed that the missing batch dimensions are
          the same for all `Y`.
  
  Returns:
      A `BatchedMultiOutputGPyTorchModel` object of the same type with
      `n + n'` training examples, representing the original model
      conditioned on the new observations `(X, Y)` (and possibly noise
      observations passed in via kwargs).
  
  Example:
      >>> train_X = torch.rand(20, 2)
      >>> train_Y = torch.cat(
      >>>     [torch.sin(train_X[:, 0]), torch.cos(train_X[:, 1])], -1
      >>> )
      >>> model = SingleTaskGP(train_X, train_Y)
      >>> new_X = torch.rand(5, 2)
      >>> new_Y = torch.cat([torch.sin(new_X[:, 0]), torch.cos(new_X[:, 1])], -1)
      >>> model = model.condition_on_observations(X=new_X, Y=new_Y)
docstr_tok: ["Condition","the","model","on","new","observations",".","Args",":","X",":","A","`","batch_shape","x","n","'","x","d","`","-dim","Tensor",",","where","`","d","`","is","the","dimension","of","the","feature","space",",","`","m","`","is","the","number","of","points","per","batch",",","and","`","batch_shape","`","is","the","batch","shape","(","must","be","compatible","with","the","batch","shape","of","the","model",")",".","Y",":","A","`","batch_shape","'","x","n","'","x","m","`","-dim","Tensor",",","where","`","m","`","is","the","number","of","model","outputs",",","`","n","'","`","is","the","number","of","points","per","batch",",","and","`","batch_shape","'","`","is","the","batch","shape","of","the","observations",".","`","batch_shape","'","`","must","be","broadcastable","to","`","batch_shape","`","using","standard","broadcasting","semantics",".","If","`","Y","`","has","fewer","batch","dimensions","than","`","X","`",",","its","is","assumed","that","the","missing","batch","dimensions","are","the","same","for","all","`","Y","`",".","Returns",":","A","`","BatchedMultiOutputGPyTorchModel","`","object","of","the","same","type","with","`","n","+","n","'","`","training","examples",",","representing","the","original","model","conditioned","on","the","new","observations","`","(","X",",","Y",")","`","(","and","possibly","noise","observations","passed","in","via","kwargs",")",".","Example",":",">",">",">","train_X","=","torch.rand","(","20",",","2",")",">",">",">","train_Y","=","torch.cat","(",">",">",">","[","torch.sin","(","train_X","[",":",",","0","]",")",",","torch.cos","(","train_X","[",":",",","1","]",")","]",",","-1",">",">",">",")",">",">",">","model","=","SingleTaskGP","(","train_X",",","train_Y",")",">",">",">","new_X","=","torch.rand","(","5",",","2",")",">",">",">","new_Y","=","torch.cat","(","[","torch.sin","(","new_X","[",":",",","0","]",")",",","torch.cos","(","new_X","[",":",",","1","]",")","]",",","-1",")",">",">",">","model","=","model.condition_on_observations","(","X=new_X",",","Y=new_Y",")"]
code: def condition_on_observations(
      self, X: Tensor, Y: Tensor, **kwargs: Any
  ) -> BatchedMultiOutputGPyTorchModel:
      r"""Condition the model on new observations.
  
      Args:
          X: A `batch_shape x n' x d`-dim Tensor, where `d` is the dimension of
              the feature space, `m` is the number of points per batch, and
              `batch_shape` is the batch shape (must be compatible with the
              batch shape of the model).
          Y: A `batch_shape' x n' x m`-dim Tensor, where `m` is the number of
              model outputs, `n'` is the number of points per batch, and
              `batch_shape'` is the batch shape of the observations.
              `batch_shape'` must be broadcastable to `batch_shape` using
              standard broadcasting semantics. If `Y` has fewer batch dimensions
              than `X`, its is assumed that the missing batch dimensions are
              the same for all `Y`.
  
      Returns:
          A `BatchedMultiOutputGPyTorchModel` object of the same type with
          `n + n'` training examples, representing the original model
          conditioned on the new observations `(X, Y)` (and possibly noise
          observations passed in via kwargs).
  
      Example:
          >>> train_X = torch.rand(20, 2)
          >>> train_Y = torch.cat(
          >>>     [torch.sin(train_X[:, 0]), torch.cos(train_X[:, 1])], -1
          >>> )
          >>> model = SingleTaskGP(train_X, train_Y)
          >>> new_X = torch.rand(5, 2)
          >>> new_Y = torch.cat([torch.sin(new_X[:, 0]), torch.cos(new_X[:, 1])], -1)
          >>> model = model.condition_on_observations(X=new_X, Y=new_Y)
      """
      noise = kwargs.get("noise")
      if hasattr(self, "outcome_transform"):
          # We need to apply transforms before shifting batch indices around.
          # `noise` is assumed to already be outcome-transformed.
          Y, _ = self.outcome_transform(Y)
      self._validate_tensor_args(X=X, Y=Y, Yvar=noise, strict=False)
      inputs = X
      if self._num_outputs > 1:
          inputs, targets, noise = multioutput_to_batch_mode_transform(
              train_X=X,
              train_Y=Y,
              num_outputs=self._num_outputs,
              train_Yvar=noise,
          )
          # `multioutput_to_batch_mode_transform` removes the output dimension,
          # which is necessary for `condition_on_observations`
          targets = targets.unsqueeze(-1)
          if noise is not None:
              noise = noise.unsqueeze(-1)
      else:
          inputs = X
          targets = Y
      if noise is not None:
          kwargs.update({"noise": noise})
      fantasy_model = super().condition_on_observations(
          X=inputs, Y=targets, **kwargs
      )
      fantasy_model._input_batch_shape = (
          fantasy_model.train_targets.shape[
              : (-1 if self._num_outputs == 1 else -2)
          ]
      )
      if not self._is_fully_bayesian:
          fantasy_model._aug_batch_shape = (
              fantasy_model.train_targets.shape[:-1]
          )
      return fantasy_model
  
imports: from __future__ import annotations
  import itertools
  import warnings
  from abc import ABC
  from copy import deepcopy
  from typing import Any, List, Optional, Tuple, TYPE_CHECKING, Union
  import torch
  from botorch.acquisition.objective import PosteriorTransform
  from botorch.exceptions.errors import BotorchTensorDimensionError, InputDataError
  from botorch.exceptions.warnings import _get_single_precision_warning, BotorchTensorDimensionWarning
  from botorch.models.model import Model, ModelList
  from botorch.models.utils import _make_X_full, add_output_dim, gpt_posterior_settings, mod_batch_shape, multioutput_to_batch_mode_transform
  from botorch.posteriors.fully_bayesian import GaussianMixturePosterior
  from botorch.posteriors.gpytorch import GPyTorchPosterior
  from botorch.utils.multitask import separate_mtmvn
  from botorch.utils.transforms import is_ensemble
  from gpytorch.distributions import MultitaskMultivariateNormal, MultivariateNormal
  from gpytorch.likelihoods.gaussian_likelihood import FixedNoiseGaussianLikelihood
  from linear_operator.operators import BlockDiagLinearOperator, CatLinearOperator
  from torch import Tensor
label_desc: Use image node_id 6 for calling the BatchedMultiOutputGPyTorchModel obj's underlying member method code with example usage: obj.condition_on_observations(X, Y) and returns: fantasy_model