class_docstr: A class that represents Random Fourier Features.
class_docstr_tok: ["A","class","that","represents","Random","Fourier","Features","."]
docstr: Initialize RandomFourierFeatures.
  
  Args:
      kernel: The GP kernel.
      input_dim: The input dimension to the GP kernel.
      num_rff_features: The number of Fourier features.
      sample_shape: The shape of a single sample. For a single-element
          `torch.Size` object, this is simply the number of RFF draws.
docstr_tok: ["Initialize","RandomFourierFeatures",".","Args",":","kernel",":","The","GP","kernel",".","input_dim",":","The","input","dimension","to","the","GP","kernel",".","num_rff_features",":","The","number","of","Fourier","features",".","sample_shape",":","The","shape","of","a","single","sample",".","For","a","single-element","`","torch.Size","`","object",",","this","is","simply","the","number","of","RFF","draws","."]
code: def __init__(
      self,
      kernel: Kernel,
      input_dim: int,
      num_rff_features: int,
      sample_shape: Optional[torch.Size] = None,
  ) -> None:
      r"""Initialize RandomFourierFeatures.
  
      Args:
          kernel: The GP kernel.
          input_dim: The input dimension to the GP kernel.
          num_rff_features: The number of Fourier features.
          sample_shape: The shape of a single sample. For a single-element
              `torch.Size` object, this is simply the number of RFF draws.
      """
      if not isinstance(kernel, ScaleKernel):
          base_kernel = kernel
          outputscale = torch.tensor(
              1.0,
              dtype=base_kernel.lengthscale.dtype,
              device=base_kernel.lengthscale.device,
          )
      else:
          base_kernel = kernel.base_kernel
          outputscale = kernel.outputscale.detach().clone()
      if not isinstance(base_kernel, (MaternKernel, RBFKernel)):
          raise NotImplementedError(
              "Only Matern and RBF kernels are supported."
          )
      super().__init__()
      self.kernel_batch_shape = base_kernel.batch_shape
      self.register_buffer("outputscale", outputscale)
  
      self.register_buffer(
          "lengthscale", base_kernel.lengthscale.detach().clone()
      )
      self.sample_shape = (
          torch.Size() if sample_shape is None else sample_shape
      )
      self.register_buffer(
          "weights",
          self._get_weights(
              base_kernel=base_kernel,
              input_dim=input_dim,
              num_rff_features=num_rff_features,
              sample_shape=self.sample_shape,
          ),
      )
      # initialize uniformly in [0, 2 * pi]
      self.register_buffer(
          "bias",
          2
          * pi
          * torch.rand(
              *self.sample_shape,
              *self.kernel_batch_shape,
              num_rff_features,
              dtype=base_kernel.lengthscale.dtype,
              device=base_kernel.lengthscale.device,
          ),
      )
  
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 1 to create a new RandomFourierFeatures object from inherited base classes: Module with example: obj = RandomFourierFeatures(kernel, input_dim, num_rff_features, sample_shape)