class_docstr: A Kernel decorator for kernels with product structure. If a kernel decomposes
  multiplicatively, then this module will be much more computationally efficient.
  
  A kernel function `k` has product structure if it can be written as
  
  .. math::
  
     \begin{equation*}
        k(\mathbf{x_1}, \mathbf{x_2}) = k'(x_1^{(1)}, x_2^{(1)}) * \ldots * k'(x_1^{(d)}, x_2^{(d)})
     \end{equation*}
  
  for some kernel :math:`k'` that operates on each dimension.
  
  Given a `b x n x d` input, `ProductStructureKernel` computes `d` one-dimensional kernels
  (using the supplied base_kernel), and then multiplies the component kernels together.
  Unlike :class:`~gpytorch.kernels.ProductKernel`, `ProductStructureKernel` computes each
  of the product terms in batch, making it very fast.
  
  See `Product Kernel Interpolation for Scalable Gaussian Processes`_ for more detail.
  
  Args:
      base_kernel (Kernel):
          The kernel to approximate with KISS-GP
      num_dims (int):
          The dimension of the input data.
      active_dims (tuple of ints, optional):
          Passed down to the `base_kernel`.
  
  .. _Product Kernel Interpolation for Scalable Gaussian Processes:
      https://arxiv.org/pdf/1802.08903
code: def num_outputs_per_input(self, x1, x2):
      return self.base_kernel.num_outputs_per_input(x1, x2)
  
file_path: gpytorch/gpytorch/kernels/product_structure_kernel.py
imports: from typing import Optional, Tuple
  from linear_operator.operators import to_linear_operator
  from .kernel import Kernel
label_desc: Use image node_id 4 for calling the ProductStructureKernel obj's underlying member method code with example usage: obj.num_outputs_per_input(x1, x2) and returns: self