# Buggy code
def __init__(
    self,
    has_lengthscale=False,
    ard_num_dims=None,
    log_lengthscale_prior=None,
    active_dims=None,
    batch_size=1,
    log_lengthscale_bounds=None,
):
    """
    The base Kernel class handles both lengthscales and ARD.

    Args:
        has_lengthscale (bool): If True, we will register a :obj:`torch.nn.Parameter` named `log_lengthscale`
        ard_num_dims (int): If not None, the `log_lengthscale` parameter will have this many entries.
        log_lengthscale_prior (:obj:`gpytorch.priors.Prior`): Prior over the log lengthscale
        active_dims (list): List of data dimensions to evaluate this Kernel on.
        batch_size (int): If training or testing multiple GPs simultaneously, this is how many lengthscales to
                          register.
        log_lengthscale_bounds (tuple): Deprecated min and max values for the lengthscales. If supplied, this
                                        now registers a :obj:`gpytorch.priors.SmoothedBoxPrior`
    """
    super(Kernel, self).__init__()
    if active_dims is not None and not torch.is_tensor(active_dims):
        active_dims = torch.tensor(active_dims, dtype=torch.long)
    self.active_dims = active_dims
    self.ard_num_dims = ard_num_dims
    self.has_lengthscale = has_lengthscale
    if has_lengthscale:
        lengthscale_num_dims = 1 if ard_num_dims is None else ard_num_dims
        log_lengthscale_prior = _bounds_to_prior(
            prior=log_lengthscale_prior, bounds=log_lengthscale_bounds
        )
        self.register_parameter(
            name="log_lengthscale",
            parameter=torch.nn.Parameter(
                torch.zeros(batch_size, 1, lengthscale_num_dims)
            ),
            prior=log_lengthscale_prior,
        )


# Traceback (RuntimeError)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-144-12b763efd692> in <module>()
19     output = model(train_x)
20     # TODO: Fix this view call!!
---> 21     loss = -mll(output, train_y)
22     loss.backward()
23     print('Iter %d/%d - Loss: %.3f' % (i + 1, n_iter, loss.item()))

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/module.py in __call__(self, *inputs, **kwargs)
160
161     def __call__(self, *inputs, **kwargs):
--> 162         outputs = self.forward(*inputs, **kwargs)
163         if torch.is_tensor(outputs) or isinstance(outputs, RandomVariable) or isinstance(outputs, LazyVariable):
164             return outputs

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/mlls/exact_marginal_log_likelihood.py in forward(self, output, target)
49
50         # Get log determininat and first part of quadratic form
---> 51         inv_quad, log_det = covar.inv_quad_log_det(inv_quad_rhs=(target - mean).unsqueeze(-1), log_det=True)
52
53         # Add terms for SGPR / when inducing points are learned

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/lazy/lazy_variable.py in inv_quad_log_det(self, inv_quad_rhs, log_det)
577         matrix_size = self.size(-1)
578         batch_size = self.size(0) if self.ndimension() == 3 else None
--> 579         tensor_cls = self.tensor_cls
580
581         args = lazy_var.representation()

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/lazy/lazy_variable.py in tensor_cls(self)
882     def tensor_cls(self):
883         if not hasattr(self, "_tensor_cls"):
--> 884             first_item = self.representation()[0]
885             if isinstance(first_item, Variable):
886                 first_item = first_item.data

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/lazy/lazy_variable.py in representation(self)
733                 representation.append(arg)
734             elif isinstance(arg, LazyVariable):
--> 735                 representation += list(arg.representation())
736             else:
737                 raise RuntimeError("Representation of a LazyVariable should consist only of Variables")

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/lazy/lazy_variable.py in representation(self)
733                 representation.append(arg)
734             elif isinstance(arg, LazyVariable):
--> 735                 representation += list(arg.representation())
736             else:
737                 raise RuntimeError("Representation of a LazyVariable should consist only of Variables")

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/lazy/lazy_evaluated_kernel_variable.py in representation(self)
109
110     def representation(self):
--> 111         return self.evaluate_kernel().representation()
112
113     def representation_tree(self):

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/lazy/lazy_evaluated_kernel_variable.py in evaluate_kernel(self)
96                 x2 = self.x2
97
---> 98             self._cached_kernel_eval = super(Kernel, self.kernel).__call__(x1, x2, **self.params)
99             if self.squeeze_row:
100                 self._cached_kernel_eval.squeeze_(-2)

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/module.py in __call__(self, *inputs, **kwargs)
160
161     def __call__(self, *inputs, **kwargs):
--> 162         outputs = self.forward(*inputs, **kwargs)
163         if torch.is_tensor(outputs) or isinstance(outputs, RandomVariable) or isinstance(outputs, LazyVariable):
164             return outputs

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/kernels/multitask_kernel.py in forward(self, x1, x2)
61     def forward(self, x1, x2):
62         covar_i = self.task_covar_module.covar_matrix
---> 63         covar_x = self.data_covar_module.forward(x1, x2)
64         if covar_x.size(0) == 1:
65             covar_x = covar_x[0]

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/kernels/grid_interpolation_kernel.py in forward(self, x1, x2, **kwargs)
52
53     def forward(self, x1, x2, **kwargs):
---> 54         base_lazy_var = self._inducing_forward()
55         if x1.size(0) > 1:
56             base_lazy_var = base_lazy_var.repeat(x1.size(0), 1, 1)

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/kernels/grid_interpolation_kernel.py in _inducing_forward(self)
46     def _inducing_forward(self):
47         inducing_points_var = Variable(self.inducing_points)
---> 48         return super(GridInterpolationKernel, self).forward(inducing_points_var, inducing_points_var)
49
50     def forward_diag(self, x1, x2, **kwargs):

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/kernels/grid_kernel.py in forward(self, x1, x2, **kwargs)
38             if settings.use_toeplitz.on():
39                 first_item = grid_var[:, 0:1].contiguous()
---> 40                 covar_columns = self.base_kernel_module(first_item, grid_var, **kwargs).evaluate()
41                 covars = [ToeplitzLazyVariable(covar_columns[i : i + 1].squeeze(-2)) for i in range(n_dim)]
42             else:

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/lazy/lazy_evaluated_kernel_variable.py in evaluate(self)
115
116     def evaluate(self):
--> 117         return self.evaluate_kernel().evaluate()
118
119     def exact_predictive_mean(self, full_mean, train_labels, n_train, likelihood, precomputed_cache=None):

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/lazy/lazy_evaluated_kernel_variable.py in evaluate_kernel(self)
96                 x2 = self.x2
97
---> 98             self._cached_kernel_eval = super(Kernel, self.kernel).__call__(x1, x2, **self.params)
99             if self.squeeze_row:
100                 self._cached_kernel_eval.squeeze_(-2)

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/module.py in __call__(self, *inputs, **kwargs)
160
161     def __call__(self, *inputs, **kwargs):
--> 162         outputs = self.forward(*inputs, **kwargs)
163         if torch.is_tensor(outputs) or isinstance(outputs, RandomVariable) or isinstance(outputs, LazyVariable):
164             return outputs

~/anaconda/envs/py3/lib/python3.6/site-packages/gpytorch/kernels/rbf_kernel.py in forward(self, x1, x2)
104     def forward(self, x1, x2):
105         lengthscales = self.log_lengthscale.exp().mul(math.sqrt(2)).clamp(self.eps, 1e5)
--> 106         diff = (x1.unsqueeze(2) - x2.unsqueeze(1)).div_(lengthscales.unsqueeze(1))
107         return diff.pow_(2).sum(-1).mul_(-1).exp_()

RuntimeError: The expanded size of the tensor (1) must match the existing size (2) at non-singleton dimension 3

# Fixed code
def __init__(
    self,
    has_lengthscale=False,
    ard_num_dims=None,
    batch_size=1,
    active_dims=None,
    log_lengthscale_bounds=None,
    log_lengthscale_prior=None,
    eps=1e-6,
):
    super(Kernel, self).__init__()
    if active_dims is not None and not torch.is_tensor(active_dims):
        active_dims = torch.tensor(active_dims, dtype=torch.long)
    self.active_dims = active_dims
    self.ard_num_dims = ard_num_dims
    self.batch_size = batch_size
    self.__has_lengthscale = has_lengthscale
    if has_lengthscale:
        lengthscale_num_dims = 1 if ard_num_dims is None else ard_num_dims
        log_lengthscale_prior = _bounds_to_prior(
            prior=log_lengthscale_prior, bounds=log_lengthscale_bounds
        )
        self.register_parameter(
            name="log_lengthscale",
            parameter=torch.nn.Parameter(
                torch.zeros(batch_size, 1, lengthscale_num_dims)
            ),
            prior=log_lengthscale_prior,
        )