class_docstr: A class that represents Random Fourier Features.
class_docstr_tok: ["A","class","that","represents","Random","Fourier","Features","."]
docstr: Get Fourier basis features for the provided inputs.
  
  Note that the right-most subset of the batch shape of `X` should
  be `(sample_shape) x (kernel_batch_shape)` if using either the
  `sample_shape` argument or a batched kernel. In other words,
  `X` should be of shape `(added_batch_shape) x (sample_shape) x
  (kernel_batch_shape) x n x input_dim`, where parantheses denote
  that the given batch shape can be empty. `X` can always be
  a tensor of shape `n x input_dim`, in which case broadcasting
  will take care of the batch shape. This will raise a `ValueError`
  if the batch shapes are not compatible.
  
  Args:
      X: Input tensor of shape `(batch_shape) x n x input_dim`.
  
  Returns:
      A Tensor of shape `(batch_shape) x n x rff`. If `X` does not have
      a `batch_shape`, the output `batch_shape` will be
      `(sample_shape) x (kernel_batch_shape)`.
docstr_tok: ["Get","Fourier","basis","features","for","the","provided","inputs",".","Note","that","the","right-most","subset","of","the","batch","shape","of","`","X","`","should","be","`","(","sample_shape",")","x","(","kernel_batch_shape",")","`","if","using","either","the","`","sample_shape","`","argument","or","a","batched","kernel",".","In","other","words",",","`","X","`","should","be","of","shape","`","(","added_batch_shape",")","x","(","sample_shape",")","x","(","kernel_batch_shape",")","x","n","x","input_dim","`",",","where","parantheses","denote","that","the","given","batch","shape","can","be","empty",".","`","X","`","can","always","be","a","tensor","of","shape","`","n","x","input_dim","`",",","in","which","case","broadcasting","will","take","care","of","the","batch","shape",".","This","will","raise","a","`","ValueError","`","if","the","batch","shapes","are","not","compatible",".","Args",":","X",":","Input","tensor","of","shape","`","(","batch_shape",")","x","n","x","input_dim","`",".","Returns",":","A","Tensor","of","shape","`","(","batch_shape",")","x","n","x","rff","`",".","If","`","X","`","does","not","have","a","`","batch_shape","`",",","the","output","`","batch_shape","`","will","be","`","(","sample_shape",")","x","(","kernel_batch_shape",")","`","."]
code: def forward(self, X: Tensor) -> Tensor:
      """Get Fourier basis features for the provided inputs.
  
      Note that the right-most subset of the batch shape of `X` should
      be `(sample_shape) x (kernel_batch_shape)` if using either the
      `sample_shape` argument or a batched kernel. In other words,
      `X` should be of shape `(added_batch_shape) x (sample_shape) x
      (kernel_batch_shape) x n x input_dim`, where parantheses denote
      that the given batch shape can be empty. `X` can always be
      a tensor of shape `n x input_dim`, in which case broadcasting
      will take care of the batch shape. This will raise a `ValueError`
      if the batch shapes are not compatible.
  
      Args:
          X: Input tensor of shape `(batch_shape) x n x input_dim`.
  
      Returns:
          A Tensor of shape `(batch_shape) x n x rff`. If `X` does not have
          a `batch_shape`, the output `batch_shape` will be
          `(sample_shape) x (kernel_batch_shape)`.
      """
      try:
          self._check_forward_X_shape_compatibility(X)
      except ValueError as e:
          # A workaround to support batched SAAS models.
          # TODO: Support batch evaluation of multi-sample RFFs as well.
          # Multi-sample RFFs have input batch as the 0-th dimension,
          # which is different than other posteriors which would have
          # the sample shape as the 0-th dimension.
          if len(self.kernel_batch_shape) == 1:
              X = X.unsqueeze(-3)
              self._check_forward_X_shape_compatibility(X)
          else:
              raise e
  
      # X is of shape (additional_batch_shape) x (sample_shape)
      # x (kernel_batch_shape) x n x d.
      # Weights is of shape (sample_shape) x (kernel_batch_shape) x d x num_rff.
      X_scaled = torch.div(X, self.lengthscale)
      batchmatmul = X_scaled @ self.weights
      bias = self.bias
      # Bias is of shape (sample_shape) x (kernel_batch_shape) x num_rff.
      # Batchmatmul is of shape (additional_batch_shape) x (sample_shape)
      # x (kernel_batch_shape) x n x num_rff.
      outputs = torch.cos(batchmatmul + bias.unsqueeze(-2))
      # Make sure we divide at the correct (i.e., kernel's) batch dimension.
      if len(self.kernel_batch_shape) > 0:
          outputscale = self.outputscale.view(
              *self.kernel_batch_shape, 1, 1
          )
      else:
          outputscale = self.outputscale
      return (
          torch.sqrt(2.0 * outputscale / self.weights.shape[-1])
          * outputs
      )
  
imports: from __future__ import annotations
  from copy import deepcopy
  from math import pi
  from typing import List, Optional
  import torch
  from botorch.models.converter import batched_to_model_list
  from botorch.models.deterministic import GenericDeterministicModel
  from botorch.models.model import Model, ModelList
  from botorch.models.model_list_gp_regression import ModelListGP
  from botorch.models.multitask import MultiTaskGP
  from botorch.utils.sampling import manual_seed
  from botorch.utils.transforms import is_ensemble
  from gpytorch.kernels import Kernel, MaternKernel, RBFKernel, ScaleKernel
  from linear_operator.utils.cholesky import psd_safe_cholesky
  from torch import Tensor
  from torch.distributions import MultivariateNormal
  from torch.nn import Module
label_desc: Use image node_id 3 for calling the RandomFourierFeatures obj's underlying member method code with example usage: obj.forward(X) and returns: unknown