We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[Bug] IndexError when GridInterpolationKernel wraps a PeriodicKernel
# 🐛 Bug

I tried to adapt the [KISS-GP for 1D data tutorial](https://gpytorch.readthedocs.io/en/latest/examples/02_Scalable_Exact_GPs/KISSGP_Regression.html#KISS-GP-for-1D-Data) to use a `PeriodicKernel` instead of an `RBFKernel`.

However, trying to evaluate the MLL fails with an `IndexError: Dimension out of range (expected to be in range of [-1, 0], but got -2)`, thrown from [grid_kernel.py: 133](https://github.com/cornellius-gp/gpytorch/blob/0317b121ebaaa921a7851a6af4f2219ff18eeaf0/gpytorch/kernels/grid_kernel.py#L133).

It seems to me this can only be a bug, as an RBF kernel and a Periodic kernel are really not very different semantically?

## To reproduce

** Code snippet to reproduce **

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Jan  7 13:52:48 2020

@author: val
"""


import math
import torch
import gpytorch

#%matplotlib inline

train_x = torch.linspace(0, 1, 1000)
train_y = torch.sin(train_x * (4 * math.pi) + torch.randn(train_x.size()) * 0.2)

class GPRegressionModel(gpytorch.models.ExactGP):
    def __init__(self, train_x, train_y, likelihood):
        super(GPRegressionModel, self).__init__(train_x, train_y, likelihood)

        # SKI requires a grid size hyperparameter. This util can help with that. Here we are using a grid that has the same number of points as the training data (a ratio of 1.0). Performance can be sensitive to this parameter, so you may want to adjust it for your own problem on a validation set.
        grid_size = gpytorch.utils.grid.choose_grid_size(train_x,1.0)

        self.mean_module = gpytorch.means.ConstantMean()
        self.covar_module = gpytorch.kernels.ScaleKernel(
            gpytorch.kernels.GridInterpolationKernel(    
                ## NOTE the only difference from the 1D KISS-GP tutorial is that the RBFKernel got replaced with a PeriodicKernel()
                gpytorch.kernels.PeriodicKernel(), #gpytorch.kernels.RBFKernel(),
                grid_size=grid_size, num_dims=1
            )
        )
        #self.covar_module = gpytorch.kernels.PeriodicKernel() 

    def forward(self, x):
        mean_x = self.mean_module(x)
        covar_x = self.covar_module(x)
        return gpytorch.distributions.MultivariateNormal(mean_x, covar_x)


likelihood = gpytorch.likelihoods.GaussianLikelihood()
model = GPRegressionModel(train_x, train_y, likelihood)

training_iterations = 1

# Find optimal model hyperparameters
model.train()
likelihood.train()

# Use the adam optimizer
optimizer = torch.optim.Adam([
    {'params': model.parameters()},  # Includes GaussianLikelihood parameters
], lr=0.1)

# "Loss" for GPs - the marginal log likelihood
mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model)

for i in range(training_iterations):
    optimizer.zero_grad()
    output = model(train_x)
    loss = -mll(output, train_y) ## NOTE fails here.
    loss.backward()
    optimizer.step()
```

** Stack trace/error message **

```
Traceback (most recent call last):

  File "<ipython-input-13-effc04c4ab77>", line 61, in <module>
    loss = -mll(output, train_y) ## NOTE fails here.

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/module.py", line 24, in __call__
    outputs = self.forward(*inputs, **kwargs)

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/mlls/exact_marginal_log_likelihood.py", line 51, in forward
    res = output.log_prob(target)

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/distributions/multivariate_normal.py", line 135, in log_prob
    inv_quad, logdet = covar.inv_quad_logdet(inv_quad_rhs=diff.unsqueeze(-1), logdet=True)

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/lazy/lazy_tensor.py", line 1038, in inv_quad_logdet
    args = self.representation()

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/lazy/lazy_tensor.py", line 1268, in representation
    representation += list(arg.representation())

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/lazy/lazy_evaluated_kernel_tensor.py", line 311, in representation
    return self.evaluate_kernel().representation()

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/utils/memoize.py", line 34, in g
    add_to_cache(self, cache_name, method(self, *args, **kwargs))

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/lazy/lazy_evaluated_kernel_tensor.py", line 278, in evaluate_kernel
    res = self.kernel(x1, x2, diag=False, last_dim_is_batch=self.last_dim_is_batch, **self.params)

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/kernel.py", line 395, in __call__
    res = super(Kernel, self).__call__(x1_, x2_, last_dim_is_batch=last_dim_is_batch, **params)

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/module.py", line 24, in __call__
    outputs = self.forward(*inputs, **kwargs)

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/scale_kernel.py", line 90, in forward
    orig_output = self.base_kernel.forward(x1, x2, diag=diag, last_dim_is_batch=last_dim_is_batch, **params)

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/grid_interpolation_kernel.py", line 177, in forward
    base_lazy_tsr = lazify(self._inducing_forward(last_dim_is_batch=last_dim_is_batch, **params))

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/grid_interpolation_kernel.py", line 143, in _inducing_forward
    return super().forward(self.grid, self.grid, last_dim_is_batch=last_dim_is_batch, **params)

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/grid_kernel.py", line 133, in forward
    covars = [ToeplitzLazyTensor(c.squeeze(-2)) for c in covars]

  File "/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/grid_kernel.py", line 133, in <listcomp>
    covars = [ToeplitzLazyTensor(c.squeeze(-2)) for c in covars]

IndexError: Dimension out of range (expected to be in range of [-1, 0], but got -2)
```

## Expected Behavior

I expected the training loop to terminate successfully, without throwing errors.


## System information

**Please complete the following information:**
- GPyTorch Version: 1.0.0
- PyTorch Version: 1.3.1
- Computer OS macOS High Sierra 10.13.3



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gpytorch/kernels/periodic_kernel.py`
Content:
```
1 #!/usr/bin/env python3
2 
3 import math
4 
5 import torch
6 
7 from ..constraints import Positive
8 from .kernel import Kernel
9 
10 
11 class PeriodicKernel(Kernel):
12     r""" Computes a covariance matrix based on the periodic kernel
13     between inputs :math:`\mathbf{x_1}` and :math:`\mathbf{x_2}`:
14 
15     .. math::
16 
17        \begin{equation*}
18           k_{\text{Periodic}}(\mathbf{x_1}, \mathbf{x_2}) = \exp \left(
19             \frac{2 \sin^2 \left( \pi \Vert \mathbf{x_1} - \mathbf{x_2} \Vert_1 / p \right) }
20             { \ell^2 } \right)
21        \end{equation*}
22 
23     where
24 
25     * :math:`p` is the periord length parameter.
26     * :math:`\ell` is a lengthscale parameter.
27 
28     .. note::
29 
30         This kernel does not have an `outputscale` parameter. To add a scaling parameter,
31         decorate this kernel with a :class:`gpytorch.kernels.ScaleKernel`.
32 
33     .. note::
34 
35         This kernel does not have an ARD lengthscale option.
36 
37     Args:
38         :attr:`batch_shape` (torch.Size, optional):
39             Set this if you want a separate lengthscale for each
40              batch of input data. It should be `b` if :attr:`x1` is a `b x n x d` tensor. Default: `torch.Size([])`.
41         :attr:`active_dims` (tuple of ints, optional):
42             Set this if you want to compute the covariance of only a few input dimensions. The ints
43             corresponds to the indices of the dimensions. Default: `None`.
44         :attr:`period_length_prior` (Prior, optional):
45             Set this if you want to apply a prior to the period length parameter.  Default: `None`.
46         :attr:`lengthscale_prior` (Prior, optional):
47             Set this if you want to apply a prior to the lengthscale parameter.  Default: `None`.
48         :attr:`lengthscale_constraint` (Constraint, optional):
49             Set this if you want to apply a constraint to the value of the lengthscale. Default: `Positive`.
50         :attr:`period_length_constraint` (Constraint, optional):
51             Set this if you want to apply a constraint to the value of the period length. Default: `Positive`.
52         :attr:`eps` (float):
53             The minimum value that the lengthscale/period length can take
54             (prevents divide by zero errors). Default: `1e-6`.
55 
56     Attributes:
57         :attr:`lengthscale` (Tensor):
58             The lengthscale parameter. Size = `*batch_shape x 1 x 1`.
59         :attr:`period_length` (Tensor):
60             The period length parameter. Size = `*batch_shape x 1 x 1`.
61 
62     Example:
63         >>> x = torch.randn(10, 5)
64         >>> # Non-batch: Simple option
65         >>> covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.PeriodicKernel())
66         >>>
67         >>> batch_x = torch.randn(2, 10, 5)
68         >>> # Batch: Simple option
69         >>> covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.PeriodicKernel())
70         >>> # Batch: different lengthscale for each batch
71         >>> covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.PeriodicKernel(batch_size=2))
72         >>> covar = covar_module(x)  # Output: LazyVariable of size (2 x 10 x 10)
73     """
74 
75     has_lengthscale = True
76 
77     def __init__(self, period_length_prior=None, period_length_constraint=None, **kwargs):
78         super(PeriodicKernel, self).__init__(**kwargs)
79         if period_length_constraint is None:
80             period_length_constraint = Positive()
81 
82         self.register_parameter(
83             name="raw_period_length", parameter=torch.nn.Parameter(torch.zeros(*self.batch_shape, 1, 1))
84         )
85 
86         if period_length_prior is not None:
87             self.register_prior(
88                 "period_length_prior",
89                 period_length_prior,
90                 lambda: self.period_length,
91                 lambda v: self._set_period_length(v),
92             )
93 
94         self.register_constraint("raw_period_length", period_length_constraint)
95 
96     @property
97     def period_length(self):
98         return self.raw_period_length_constraint.transform(self.raw_period_length)
99 
100     @period_length.setter
101     def period_length(self, value):
102         self._set_period_length(value)
103 
104     def _set_period_length(self, value):
105         if not torch.is_tensor(value):
106             value = torch.as_tensor(value).to(self.raw_period_length)
107         self.initialize(raw_period_length=self.raw_period_length_constraint.inverse_transform(value))
108 
109     def forward(self, x1, x2, diag=False, **params):
110         x1_ = x1.div(self.period_length)
111         x2_ = x2.div(self.period_length)
112         diff = self.covar_dist(x1_, x2_, diag=diag, **params)
113         res = torch.sin(diff.mul(math.pi)).pow(2).mul(-2 / self.lengthscale).exp_()
114         if diff.ndimension() == 2 or diag:
115             res = res.squeeze(0)
116         return res
117
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/gpytorch/kernels/periodic_kernel.py b/gpytorch/kernels/periodic_kernel.py
--- a/gpytorch/kernels/periodic_kernel.py
+++ b/gpytorch/kernels/periodic_kernel.py
@@ -111,6 +111,6 @@
         x2_ = x2.div(self.period_length)
         diff = self.covar_dist(x1_, x2_, diag=diag, **params)
         res = torch.sin(diff.mul(math.pi)).pow(2).mul(-2 / self.lengthscale).exp_()
-        if diff.ndimension() == 2 or diag:
+        if diag:
             res = res.squeeze(0)
         return res

{"golden_diff": "diff --git a/gpytorch/kernels/periodic_kernel.py b/gpytorch/kernels/periodic_kernel.py\n--- a/gpytorch/kernels/periodic_kernel.py\n+++ b/gpytorch/kernels/periodic_kernel.py\n@@ -111,6 +111,6 @@\n         x2_ = x2.div(self.period_length)\n         diff = self.covar_dist(x1_, x2_, diag=diag, **params)\n         res = torch.sin(diff.mul(math.pi)).pow(2).mul(-2 / self.lengthscale).exp_()\n-        if diff.ndimension() == 2 or diag:\n+        if diag:\n             res = res.squeeze(0)\n         return res\n", "issue": "[Bug] IndexError when GridInterpolationKernel wraps a PeriodicKernel\n# \ud83d\udc1b Bug\r\n\r\nI tried to adapt the [KISS-GP for 1D data tutorial](https://gpytorch.readthedocs.io/en/latest/examples/02_Scalable_Exact_GPs/KISSGP_Regression.html#KISS-GP-for-1D-Data) to use a `PeriodicKernel` instead of an `RBFKernel`.\r\n\r\nHowever, trying to evaluate the MLL fails with an `IndexError: Dimension out of range (expected to be in range of [-1, 0], but got -2)`, thrown from [grid_kernel.py: 133](https://github.com/cornellius-gp/gpytorch/blob/0317b121ebaaa921a7851a6af4f2219ff18eeaf0/gpytorch/kernels/grid_kernel.py#L133).\r\n\r\nIt seems to me this can only be a bug, as an RBF kernel and a Periodic kernel are really not very different semantically?\r\n\r\n## To reproduce\r\n\r\n** Code snippet to reproduce **\r\n\r\n```python\r\n#!/usr/bin/env python3\r\n# -*- coding: utf-8 -*-\r\n\"\"\"\r\nCreated on Tue Jan  7 13:52:48 2020\r\n\r\n@author: val\r\n\"\"\"\r\n\r\n\r\nimport math\r\nimport torch\r\nimport gpytorch\r\n\r\n#%matplotlib inline\r\n\r\ntrain_x = torch.linspace(0, 1, 1000)\r\ntrain_y = torch.sin(train_x * (4 * math.pi) + torch.randn(train_x.size()) * 0.2)\r\n\r\nclass GPRegressionModel(gpytorch.models.ExactGP):\r\n    def __init__(self, train_x, train_y, likelihood):\r\n        super(GPRegressionModel, self).__init__(train_x, train_y, likelihood)\r\n\r\n        # SKI requires a grid size hyperparameter. This util can help with that. Here we are using a grid that has the same number of points as the training data (a ratio of 1.0). Performance can be sensitive to this parameter, so you may want to adjust it for your own problem on a validation set.\r\n        grid_size = gpytorch.utils.grid.choose_grid_size(train_x,1.0)\r\n\r\n        self.mean_module = gpytorch.means.ConstantMean()\r\n        self.covar_module = gpytorch.kernels.ScaleKernel(\r\n            gpytorch.kernels.GridInterpolationKernel(    \r\n                ## NOTE the only difference from the 1D KISS-GP tutorial is that the RBFKernel got replaced with a PeriodicKernel()\r\n                gpytorch.kernels.PeriodicKernel(), #gpytorch.kernels.RBFKernel(),\r\n                grid_size=grid_size, num_dims=1\r\n            )\r\n        )\r\n        #self.covar_module = gpytorch.kernels.PeriodicKernel() \r\n\r\n    def forward(self, x):\r\n        mean_x = self.mean_module(x)\r\n        covar_x = self.covar_module(x)\r\n        return gpytorch.distributions.MultivariateNormal(mean_x, covar_x)\r\n\r\n\r\nlikelihood = gpytorch.likelihoods.GaussianLikelihood()\r\nmodel = GPRegressionModel(train_x, train_y, likelihood)\r\n\r\ntraining_iterations = 1\r\n\r\n# Find optimal model hyperparameters\r\nmodel.train()\r\nlikelihood.train()\r\n\r\n# Use the adam optimizer\r\noptimizer = torch.optim.Adam([\r\n    {'params': model.parameters()},  # Includes GaussianLikelihood parameters\r\n], lr=0.1)\r\n\r\n# \"Loss\" for GPs - the marginal log likelihood\r\nmll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model)\r\n\r\nfor i in range(training_iterations):\r\n    optimizer.zero_grad()\r\n    output = model(train_x)\r\n    loss = -mll(output, train_y) ## NOTE fails here.\r\n    loss.backward()\r\n    optimizer.step()\r\n```\r\n\r\n** Stack trace/error message **\r\n\r\n```\r\nTraceback (most recent call last):\r\n\r\n  File \"<ipython-input-13-effc04c4ab77>\", line 61, in <module>\r\n    loss = -mll(output, train_y) ## NOTE fails here.\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/module.py\", line 24, in __call__\r\n    outputs = self.forward(*inputs, **kwargs)\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/mlls/exact_marginal_log_likelihood.py\", line 51, in forward\r\n    res = output.log_prob(target)\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/distributions/multivariate_normal.py\", line 135, in log_prob\r\n    inv_quad, logdet = covar.inv_quad_logdet(inv_quad_rhs=diff.unsqueeze(-1), logdet=True)\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/lazy/lazy_tensor.py\", line 1038, in inv_quad_logdet\r\n    args = self.representation()\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/lazy/lazy_tensor.py\", line 1268, in representation\r\n    representation += list(arg.representation())\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/lazy/lazy_evaluated_kernel_tensor.py\", line 311, in representation\r\n    return self.evaluate_kernel().representation()\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/utils/memoize.py\", line 34, in g\r\n    add_to_cache(self, cache_name, method(self, *args, **kwargs))\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/lazy/lazy_evaluated_kernel_tensor.py\", line 278, in evaluate_kernel\r\n    res = self.kernel(x1, x2, diag=False, last_dim_is_batch=self.last_dim_is_batch, **self.params)\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/kernel.py\", line 395, in __call__\r\n    res = super(Kernel, self).__call__(x1_, x2_, last_dim_is_batch=last_dim_is_batch, **params)\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/module.py\", line 24, in __call__\r\n    outputs = self.forward(*inputs, **kwargs)\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/scale_kernel.py\", line 90, in forward\r\n    orig_output = self.base_kernel.forward(x1, x2, diag=diag, last_dim_is_batch=last_dim_is_batch, **params)\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/grid_interpolation_kernel.py\", line 177, in forward\r\n    base_lazy_tsr = lazify(self._inducing_forward(last_dim_is_batch=last_dim_is_batch, **params))\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/grid_interpolation_kernel.py\", line 143, in _inducing_forward\r\n    return super().forward(self.grid, self.grid, last_dim_is_batch=last_dim_is_batch, **params)\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/grid_kernel.py\", line 133, in forward\r\n    covars = [ToeplitzLazyTensor(c.squeeze(-2)) for c in covars]\r\n\r\n  File \"/Users/val/opt/anaconda3/lib/python3.7/site-packages/gpytorch/kernels/grid_kernel.py\", line 133, in <listcomp>\r\n    covars = [ToeplitzLazyTensor(c.squeeze(-2)) for c in covars]\r\n\r\nIndexError: Dimension out of range (expected to be in range of [-1, 0], but got -2)\r\n```\r\n\r\n## Expected Behavior\r\n\r\nI expected the training loop to terminate successfully, without throwing errors.\r\n\r\n\r\n## System information\r\n\r\n**Please complete the following information:**\r\n- GPyTorch Version: 1.0.0\r\n- PyTorch Version: 1.3.1\r\n- Computer OS macOS High Sierra 10.13.3\r\n\r\n\n", "before_files": [{"content": "#!/usr/bin/env python3\n\nimport math\n\nimport torch\n\nfrom ..constraints import Positive\nfrom .kernel import Kernel\n\n\nclass PeriodicKernel(Kernel):\n    r\"\"\" Computes a covariance matrix based on the periodic kernel\n    between inputs :math:`\\mathbf{x_1}` and :math:`\\mathbf{x_2}`:\n\n    .. math::\n\n       \\begin{equation*}\n          k_{\\text{Periodic}}(\\mathbf{x_1}, \\mathbf{x_2}) = \\exp \\left(\n            \\frac{2 \\sin^2 \\left( \\pi \\Vert \\mathbf{x_1} - \\mathbf{x_2} \\Vert_1 / p \\right) }\n            { \\ell^2 } \\right)\n       \\end{equation*}\n\n    where\n\n    * :math:`p` is the periord length parameter.\n    * :math:`\\ell` is a lengthscale parameter.\n\n    .. note::\n\n        This kernel does not have an `outputscale` parameter. To add a scaling parameter,\n        decorate this kernel with a :class:`gpytorch.kernels.ScaleKernel`.\n\n    .. note::\n\n        This kernel does not have an ARD lengthscale option.\n\n    Args:\n        :attr:`batch_shape` (torch.Size, optional):\n            Set this if you want a separate lengthscale for each\n             batch of input data. It should be `b` if :attr:`x1` is a `b x n x d` tensor. Default: `torch.Size([])`.\n        :attr:`active_dims` (tuple of ints, optional):\n            Set this if you want to compute the covariance of only a few input dimensions. The ints\n            corresponds to the indices of the dimensions. Default: `None`.\n        :attr:`period_length_prior` (Prior, optional):\n            Set this if you want to apply a prior to the period length parameter.  Default: `None`.\n        :attr:`lengthscale_prior` (Prior, optional):\n            Set this if you want to apply a prior to the lengthscale parameter.  Default: `None`.\n        :attr:`lengthscale_constraint` (Constraint, optional):\n            Set this if you want to apply a constraint to the value of the lengthscale. Default: `Positive`.\n        :attr:`period_length_constraint` (Constraint, optional):\n            Set this if you want to apply a constraint to the value of the period length. Default: `Positive`.\n        :attr:`eps` (float):\n            The minimum value that the lengthscale/period length can take\n            (prevents divide by zero errors). Default: `1e-6`.\n\n    Attributes:\n        :attr:`lengthscale` (Tensor):\n            The lengthscale parameter. Size = `*batch_shape x 1 x 1`.\n        :attr:`period_length` (Tensor):\n            The period length parameter. Size = `*batch_shape x 1 x 1`.\n\n    Example:\n        >>> x = torch.randn(10, 5)\n        >>> # Non-batch: Simple option\n        >>> covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.PeriodicKernel())\n        >>>\n        >>> batch_x = torch.randn(2, 10, 5)\n        >>> # Batch: Simple option\n        >>> covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.PeriodicKernel())\n        >>> # Batch: different lengthscale for each batch\n        >>> covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.PeriodicKernel(batch_size=2))\n        >>> covar = covar_module(x)  # Output: LazyVariable of size (2 x 10 x 10)\n    \"\"\"\n\n    has_lengthscale = True\n\n    def __init__(self, period_length_prior=None, period_length_constraint=None, **kwargs):\n        super(PeriodicKernel, self).__init__(**kwargs)\n        if period_length_constraint is None:\n            period_length_constraint = Positive()\n\n        self.register_parameter(\n            name=\"raw_period_length\", parameter=torch.nn.Parameter(torch.zeros(*self.batch_shape, 1, 1))\n        )\n\n        if period_length_prior is not None:\n            self.register_prior(\n                \"period_length_prior\",\n                period_length_prior,\n                lambda: self.period_length,\n                lambda v: self._set_period_length(v),\n            )\n\n        self.register_constraint(\"raw_period_length\", period_length_constraint)\n\n    @property\n    def period_length(self):\n        return self.raw_period_length_constraint.transform(self.raw_period_length)\n\n    @period_length.setter\n    def period_length(self, value):\n        self._set_period_length(value)\n\n    def _set_period_length(self, value):\n        if not torch.is_tensor(value):\n            value = torch.as_tensor(value).to(self.raw_period_length)\n        self.initialize(raw_period_length=self.raw_period_length_constraint.inverse_transform(value))\n\n    def forward(self, x1, x2, diag=False, **params):\n        x1_ = x1.div(self.period_length)\n        x2_ = x2.div(self.period_length)\n        diff = self.covar_dist(x1_, x2_, diag=diag, **params)\n        res = torch.sin(diff.mul(math.pi)).pow(2).mul(-2 / self.lengthscale).exp_()\n        if diff.ndimension() == 2 or diag:\n            res = res.squeeze(0)\n        return res\n", "path": "gpytorch/kernels/periodic_kernel.py"}], "after_files": [{"content": "#!/usr/bin/env python3\n\nimport math\n\nimport torch\n\nfrom ..constraints import Positive\nfrom .kernel import Kernel\n\n\nclass PeriodicKernel(Kernel):\n    r\"\"\" Computes a covariance matrix based on the periodic kernel\n    between inputs :math:`\\mathbf{x_1}` and :math:`\\mathbf{x_2}`:\n\n    .. math::\n\n       \\begin{equation*}\n          k_{\\text{Periodic}}(\\mathbf{x_1}, \\mathbf{x_2}) = \\exp \\left(\n            \\frac{2 \\sin^2 \\left( \\pi \\Vert \\mathbf{x_1} - \\mathbf{x_2} \\Vert_1 / p \\right) }\n            { \\ell^2 } \\right)\n       \\end{equation*}\n\n    where\n\n    * :math:`p` is the periord length parameter.\n    * :math:`\\ell` is a lengthscale parameter.\n\n    .. note::\n\n        This kernel does not have an `outputscale` parameter. To add a scaling parameter,\n        decorate this kernel with a :class:`gpytorch.kernels.ScaleKernel`.\n\n    .. note::\n\n        This kernel does not have an ARD lengthscale option.\n\n    Args:\n        :attr:`batch_shape` (torch.Size, optional):\n            Set this if you want a separate lengthscale for each\n             batch of input data. It should be `b` if :attr:`x1` is a `b x n x d` tensor. Default: `torch.Size([])`.\n        :attr:`active_dims` (tuple of ints, optional):\n            Set this if you want to compute the covariance of only a few input dimensions. The ints\n            corresponds to the indices of the dimensions. Default: `None`.\n        :attr:`period_length_prior` (Prior, optional):\n            Set this if you want to apply a prior to the period length parameter.  Default: `None`.\n        :attr:`lengthscale_prior` (Prior, optional):\n            Set this if you want to apply a prior to the lengthscale parameter.  Default: `None`.\n        :attr:`lengthscale_constraint` (Constraint, optional):\n            Set this if you want to apply a constraint to the value of the lengthscale. Default: `Positive`.\n        :attr:`period_length_constraint` (Constraint, optional):\n            Set this if you want to apply a constraint to the value of the period length. Default: `Positive`.\n        :attr:`eps` (float):\n            The minimum value that the lengthscale/period length can take\n            (prevents divide by zero errors). Default: `1e-6`.\n\n    Attributes:\n        :attr:`lengthscale` (Tensor):\n            The lengthscale parameter. Size = `*batch_shape x 1 x 1`.\n        :attr:`period_length` (Tensor):\n            The period length parameter. Size = `*batch_shape x 1 x 1`.\n\n    Example:\n        >>> x = torch.randn(10, 5)\n        >>> # Non-batch: Simple option\n        >>> covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.PeriodicKernel())\n        >>>\n        >>> batch_x = torch.randn(2, 10, 5)\n        >>> # Batch: Simple option\n        >>> covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.PeriodicKernel())\n        >>> # Batch: different lengthscale for each batch\n        >>> covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.PeriodicKernel(batch_size=2))\n        >>> covar = covar_module(x)  # Output: LazyVariable of size (2 x 10 x 10)\n    \"\"\"\n\n    has_lengthscale = True\n\n    def __init__(self, period_length_prior=None, period_length_constraint=None, **kwargs):\n        super(PeriodicKernel, self).__init__(**kwargs)\n        if period_length_constraint is None:\n            period_length_constraint = Positive()\n\n        self.register_parameter(\n            name=\"raw_period_length\", parameter=torch.nn.Parameter(torch.zeros(*self.batch_shape, 1, 1))\n        )\n\n        if period_length_prior is not None:\n            self.register_prior(\n                \"period_length_prior\",\n                period_length_prior,\n                lambda: self.period_length,\n                lambda v: self._set_period_length(v),\n            )\n\n        self.register_constraint(\"raw_period_length\", period_length_constraint)\n\n    @property\n    def period_length(self):\n        return self.raw_period_length_constraint.transform(self.raw_period_length)\n\n    @period_length.setter\n    def period_length(self, value):\n        self._set_period_length(value)\n\n    def _set_period_length(self, value):\n        if not torch.is_tensor(value):\n            value = torch.as_tensor(value).to(self.raw_period_length)\n        self.initialize(raw_period_length=self.raw_period_length_constraint.inverse_transform(value))\n\n    def forward(self, x1, x2, diag=False, **params):\n        x1_ = x1.div(self.period_length)\n        x2_ = x2.div(self.period_length)\n        diff = self.covar_dist(x1_, x2_, diag=diag, **params)\n        res = torch.sin(diff.mul(math.pi)).pow(2).mul(-2 / self.lengthscale).exp_()\n        if diag:\n            res = res.squeeze(0)\n        return res\n", "path": "gpytorch/kernels/periodic_kernel.py"}]}