class_docstr: Computes a covariance matrix based on the Spectral Mixture Kernel
  between inputs :math:`\mathbf{x_1}` and :math:`\mathbf{x_2}`.
  
  It was proposed in `Gaussian Process Kernels for Pattern Discovery and Extrapolation`_.
  
  .. note::
      Unlike other kernels,
  
          * ard_num_dims **must equal** the number of dimensions of the data.
          * This kernel should not be combined with a :class:`gpytorch.kernels.ScaleKernel`.
  
  :param int num_mixtures: The number of components in the mixture.
  :param int ard_num_dims: Set this to match the dimensionality of the input.
      It should be `d` if x1 is a `... x n x d` matrix. (Default: `1`.)
  :param batch_shape: Set this if the data is batch of input data. It should
      be `b_1 x ... x b_j` if x1 is a `b_1 x ... x b_j x n x d` tensor. (Default: `torch.Size([])`.)
  :type batch_shape: torch.Size, optional
  :param active_dims: Set this if you want to compute the covariance of only
      a few input dimensions. The ints corresponds to the indices of the dimensions. (Default: `None`.)
  :type active_dims: float, optional
  :param eps: The minimum value that the lengthscale can take (prevents divide by zero errors). (Default: `1e-6`.)
  :type eps: float, optional
  
  :param mixture_scales_prior: A prior to set on the mixture_scales parameter
  :type mixture_scales_prior: ~gpytorch.priors.Prior, optional
  :param mixture_scales_constraint: A constraint to set on the mixture_scales parameter
  :type mixture_scales_constraint: ~gpytorch.constraints.Interval, optional
  :param mixture_means_prior: A prior to set on the mixture_means parameter
  :type mixture_means_prior: ~gpytorch.priors.Prior, optional
  :param mixture_means_constraint: A constraint to set on the mixture_means parameter
  :type mixture_means_constraint: ~gpytorch.constraints.Interval, optional
  :param mixture_weights_prior: A prior to set on the mixture_weights parameter
  :type mixture_weights_prior: ~gpytorch.priors.Prior, optional
  :param mixture_weights_constraint: A constraint to set on the mixture_weights parameter
  :type mixture_weights_constraint: ~gpytorch.constraints.Interval, optional
  
  :ivar torch.Tensor mixture_scales: The lengthscale parameter. Given
      `k` mixture components, and `... x n x d` data, this will be of size `... x k x 1 x d`.
  :ivar torch.Tensor mixture_means: The mixture mean parameters (`... x k x 1 x d`).
  :ivar torch.Tensor mixture_weights: The mixture weight parameters (`... x k`).
  
  Example:
  
      >>> # Non-batch
      >>> x = torch.randn(10, 5)
      >>> covar_module = gpytorch.kernels.SpectralMixtureKernel(num_mixtures=4, ard_num_dims=5)
      >>> covar = covar_module(x)  # Output: LazyVariable of size (10 x 10)
      >>>
      >>> # Batch
      >>> batch_x = torch.randn(2, 10, 5)
      >>> covar_module = gpytorch.kernels.SpectralMixtureKernel(num_mixtures=4, batch_size=2, ard_num_dims=5)
      >>> covar = covar_module(x)  # Output: LazyVariable of size (10 x 10)
  
  .. _Gaussian Process Kernels for Pattern Discovery and Extrapolation:
      https://arxiv.org/pdf/1302.4245.pdf
docstr: Initialize mixture components based on batch statistics of the data. You should use
  this initialization routine if your observations are not evenly spaced.
  
  :param torch.Tensor train_x: Training inputs
  :param torch.Tensor train_y: Training outputs
docstr_tok: ["Initialize","mixture","components","based","on","batch","statistics","of","the","data",".","You","should","use","this","initialization","routine","if","your","observations","are","not","evenly","spaced",".",":","param","torch.Tensor","train_x",":","Training","inputs",":","param","torch.Tensor","train_y",":","Training","outputs"]
code: def initialize_from_data(
      self, train_x: torch.Tensor, train_y: torch.Tensor, **kwargs
  ):
      """
      Initialize mixture components based on batch statistics of the data. You should use
      this initialization routine if your observations are not evenly spaced.
  
      :param torch.Tensor train_x: Training inputs
      :param torch.Tensor train_y: Training outputs
      """
  
      with torch.no_grad():
          if not torch.is_tensor(train_x) or not torch.is_tensor(
              train_y
          ):
              raise RuntimeError(
                  "train_x and train_y should be tensors"
              )
          if train_x.ndimension() == 1:
              train_x = train_x.unsqueeze(-1)
          if self.active_dims is not None:
              train_x = train_x[..., self.active_dims]
  
          # Compute maximum distance between points in each dimension
          train_x_sort = train_x.sort(dim=-2)[0]
          max_dist = train_x_sort[..., -1, :] - train_x_sort[..., 0, :]
  
          # Compute the minimum distance between points in each dimension
          dists = train_x_sort[..., 1:, :] - train_x_sort[..., :-1, :]
          # We don't want the minimum distance to be zero, so fill zero values with some large number
          dists = torch.where(
              dists.eq(0.0),
              torch.tensor(
                  1.0e10, dtype=train_x.dtype, device=train_x.device
              ),
              dists,
          )
          sorted_dists = dists.sort(dim=-2)[0]
          min_dist = sorted_dists[..., 0, :]
  
          # Reshape min_dist and max_dist to match the shape of parameters
          # First add a singleton data dimension (-2) and a dimension for the mixture components (-3)
          min_dist = min_dist.unsqueeze_(-2).unsqueeze_(-3)
          max_dist = max_dist.unsqueeze_(-2).unsqueeze_(-3)
          # Compress any dimensions in min_dist/max_dist that correspond to singletons in the SM parameters
          dim = -3
          while -dim <= min_dist.dim():
              if -dim > self.raw_mixture_scales.dim():
                  min_dist = min_dist.min(dim=dim)[0]
                  max_dist = max_dist.max(dim=dim)[0]
              elif self.raw_mixture_scales.size(dim) == 1:
                  min_dist = min_dist.min(dim=dim, keepdim=True)[0]
                  max_dist = max_dist.max(dim=dim, keepdim=True)[0]
                  dim -= 1
              else:
                  dim -= 1
  
          # Inverse of lengthscales should be drawn from truncated Gaussian | N(0, max_dist^2) |
          self.mixture_scales = (
              torch.randn_like(self.raw_mixture_scales)
              .mul_(max_dist)
              .abs_()
              .reciprocal_()
          )
          # Draw means from Unif(0, 0.5 / minimum distance between two points)
          self.mixture_means = (
              torch.rand_like(self.raw_mixture_means)
              .mul_(0.5)
              .div(min_dist)
          )
          # Mixture weights should be roughly the stdv of the y values divided by the number of mixtures
          self.mixture_weights = train_y.std().div(self.num_mixtures)
  
imports: import logging
  import math
  from typing import Optional, Tuple, Union
  import torch
  from ..constraints import Interval, Positive
  from ..priors import Prior
  from .kernel import Kernel
label_desc: Use image node_id 12 for calling the SpectralMixtureKernel obj's underlying member method code with example usage: obj.initialize_from_data(train_x, train_y) without return types