We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Anisotropic lengthscales
Currently, by default, all stationary kernels impose a positive transform on the lengthscales Parameter. For the case of AnisotropicStationary kernels, this reduces the viable parameter space by a factor of 2^(D-1), where D is the number of input dimensions. So it is acceptable in the case of a 1D problem, but in higher dimensions we would miss out. For example, for the Cosine kernel there is a significant difference between lengthscales of [+1, +1], and [+1, -1], they correspond to waves propagating in perpendicular directions. 


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gpflow/kernels/stationaries.py`
Content:
```
1 # Copyright 2017-2020 The GPflow Contributors. All Rights Reserved.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 from typing import Any, Optional
16 
17 import numpy as np
18 import tensorflow as tf
19 
20 from ..base import Parameter, TensorType
21 from ..utilities import positive
22 from ..utilities.ops import difference_matrix, square_distance
23 from .base import ActiveDims, Kernel
24 
25 
26 class Stationary(Kernel):
27     """
28     Base class for kernels that are stationary, that is, they only depend on
29 
30         d = x - x'
31 
32     This class handles 'ard' behaviour, which stands for 'Automatic Relevance
33     Determination'. This means that the kernel has one lengthscale per
34     dimension, otherwise the kernel is isotropic (has a single lengthscale).
35     """
36 
37     def __init__(
38         self, variance: TensorType = 1.0, lengthscales: TensorType = 1.0, **kwargs: Any
39     ) -> None:
40         """
41         :param variance: the (initial) value for the variance parameter.
42         :param lengthscales: the (initial) value for the lengthscale
43             parameter(s), to induce ARD behaviour this must be initialised as
44             an array the same length as the the number of active dimensions
45             e.g. [1., 1., 1.]. If only a single value is passed, this value
46             is used as the lengthscale of each dimension.
47         :param kwargs: accepts `name` and `active_dims`, which is a list or
48             slice of indices which controls which columns of X are used (by
49             default, all columns are used).
50         """
51         for kwarg in kwargs:
52             if kwarg not in {"name", "active_dims"}:
53                 raise TypeError(f"Unknown keyword argument: {kwarg}")
54 
55         super().__init__(**kwargs)
56         self.variance = Parameter(variance, transform=positive())
57         self.lengthscales = Parameter(lengthscales, transform=positive())
58         self._validate_ard_active_dims(self.lengthscales)
59 
60     @property
61     def ard(self) -> bool:
62         """
63         Whether ARD behaviour is active.
64         """
65         ndims: int = self.lengthscales.shape.ndims
66         return ndims > 0
67 
68     def scale(self, X: TensorType) -> TensorType:
69         X_scaled = X / self.lengthscales if X is not None else X
70         return X_scaled
71 
72     def K_diag(self, X: TensorType) -> tf.Tensor:
73         return tf.fill(tf.shape(X)[:-1], tf.squeeze(self.variance))
74 
75 
76 class IsotropicStationary(Stationary):
77     """
78     Base class for isotropic stationary kernels, i.e. kernels that only
79     depend on
80 
81         r = ‖x - x'‖
82 
83     Derived classes should implement one of:
84 
85         K_r2(self, r2): Returns the kernel evaluated on r² (r2), which is the
86         squared scaled Euclidean distance Should operate element-wise on r2.
87 
88         K_r(self, r): Returns the kernel evaluated on r, which is the scaled
89         Euclidean distance. Should operate element-wise on r.
90     """
91 
92     def K(self, X: TensorType, X2: Optional[TensorType] = None) -> tf.Tensor:
93         r2 = self.scaled_squared_euclid_dist(X, X2)
94         return self.K_r2(r2)
95 
96     def K_r2(self, r2: TensorType) -> tf.Tensor:
97         if hasattr(self, "K_r"):
98             # Clipping around the (single) float precision which is ~1e-45.
99             r = tf.sqrt(tf.maximum(r2, 1e-36))
100             return self.K_r(r)  # pylint: disable=no-member
101         raise NotImplementedError
102 
103     def scaled_squared_euclid_dist(
104         self, X: TensorType, X2: Optional[TensorType] = None
105     ) -> tf.Tensor:
106         """
107         Returns ‖(X - X2ᵀ) / ℓ‖², i.e. the squared L₂-norm.
108         """
109         return square_distance(self.scale(X), self.scale(X2))
110 
111 
112 class AnisotropicStationary(Stationary):
113     """
114     Base class for anisotropic stationary kernels, i.e. kernels that only
115     depend on
116 
117         d = x - x'
118 
119     Derived classes should implement K_d(self, d): Returns the kernel evaluated
120     on d, which is the pairwise difference matrix, scaled by the lengthscale
121     parameter ℓ (i.e. [(X - X2ᵀ) / ℓ]). The last axis corresponds to the
122     input dimension.
123     """
124 
125     def K(self, X: TensorType, X2: Optional[TensorType] = None) -> tf.Tensor:
126         return self.K_d(self.scaled_difference_matrix(X, X2))
127 
128     def scaled_difference_matrix(self, X: TensorType, X2: Optional[TensorType] = None) -> tf.Tensor:
129         """
130         Returns [(X - X2ᵀ) / ℓ]. If X has shape [..., N, D] and
131         X2 has shape [..., M, D], the output will have shape [..., N, M, D].
132         """
133         return difference_matrix(self.scale(X), self.scale(X2))
134 
135     def K_d(self, d: TensorType) -> tf.Tensor:
136         raise NotImplementedError
137 
138 
139 class SquaredExponential(IsotropicStationary):
140     """
141     The radial basis function (RBF) or squared exponential kernel. The kernel equation is
142 
143         k(r) = σ² exp{-½ r²}
144 
145     where:
146     r   is the Euclidean distance between the input points, scaled by the lengthscales parameter ℓ.
147     σ²  is the variance parameter
148 
149     Functions drawn from a GP with this kernel are infinitely differentiable!
150     """
151 
152     def K_r2(self, r2: TensorType) -> tf.Tensor:
153         return self.variance * tf.exp(-0.5 * r2)
154 
155 
156 class RationalQuadratic(IsotropicStationary):
157     """
158     Rational Quadratic kernel,
159 
160     k(r) = σ² (1 + r² / 2αℓ²)^(-α)
161 
162     σ² : variance
163     ℓ  : lengthscales
164     α  : alpha, determines relative weighting of small-scale and large-scale fluctuations
165 
166     For α → ∞, the RQ kernel becomes equivalent to the squared exponential.
167     """
168 
169     def __init__(
170         self,
171         variance: TensorType = 1.0,
172         lengthscales: TensorType = 1.0,
173         alpha: TensorType = 1.0,
174         active_dims: Optional[ActiveDims] = None,
175     ) -> None:
176         super().__init__(variance=variance, lengthscales=lengthscales, active_dims=active_dims)
177         self.alpha = Parameter(alpha, transform=positive())
178 
179     def K_r2(self, r2: TensorType) -> tf.Tensor:
180         return self.variance * (1 + 0.5 * r2 / self.alpha) ** (-self.alpha)
181 
182 
183 class Exponential(IsotropicStationary):
184     """
185     The Exponential kernel. It is equivalent to a Matern12 kernel with doubled lengthscales.
186     """
187 
188     def K_r(self, r: TensorType) -> tf.Tensor:
189         return self.variance * tf.exp(-0.5 * r)
190 
191 
192 class Matern12(IsotropicStationary):
193     """
194     The Matern 1/2 kernel. Functions drawn from a GP with this kernel are not
195     differentiable anywhere. The kernel equation is
196 
197     k(r) = σ² exp{-r}
198 
199     where:
200     r  is the Euclidean distance between the input points, scaled by the lengthscales parameter ℓ.
201     σ² is the variance parameter
202     """
203 
204     def K_r(self, r: TensorType) -> tf.Tensor:
205         return self.variance * tf.exp(-r)
206 
207 
208 class Matern32(IsotropicStationary):
209     """
210     The Matern 3/2 kernel. Functions drawn from a GP with this kernel are once
211     differentiable. The kernel equation is
212 
213     k(r) = σ² (1 + √3r) exp{-√3 r}
214 
215     where:
216     r  is the Euclidean distance between the input points, scaled by the lengthscales parameter ℓ,
217     σ² is the variance parameter.
218     """
219 
220     def K_r(self, r: TensorType) -> tf.Tensor:
221         sqrt3 = np.sqrt(3.0)
222         return self.variance * (1.0 + sqrt3 * r) * tf.exp(-sqrt3 * r)
223 
224 
225 class Matern52(IsotropicStationary):
226     """
227     The Matern 5/2 kernel. Functions drawn from a GP with this kernel are twice
228     differentiable. The kernel equation is
229 
230     k(r) = σ² (1 + √5r + 5/3r²) exp{-√5 r}
231 
232     where:
233     r  is the Euclidean distance between the input points, scaled by the lengthscales parameter ℓ,
234     σ² is the variance parameter.
235     """
236 
237     def K_r(self, r: TensorType) -> tf.Tensor:
238         sqrt5 = np.sqrt(5.0)
239         return self.variance * (1.0 + sqrt5 * r + 5.0 / 3.0 * tf.square(r)) * tf.exp(-sqrt5 * r)
240 
241 
242 class Cosine(AnisotropicStationary):
243     """
244     The Cosine kernel. Functions drawn from a GP with this kernel are sinusoids
245     (with a random phase).  The kernel equation is
246 
247         k(r) = σ² cos{2πd}
248 
249     where:
250     d  is the sum of the per-dimension differences between the input points, scaled by the
251     lengthscale parameter ℓ (i.e. Σᵢ [(X - X2ᵀ) / ℓ]ᵢ),
252     σ² is the variance parameter.
253     """
254 
255     def K_d(self, d: TensorType) -> tf.Tensor:
256         d = tf.reduce_sum(d, axis=-1)
257         return self.variance * tf.cos(2 * np.pi * d)
258
```
--- 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/gpflow/kernels/stationaries.py b/gpflow/kernels/stationaries.py
--- a/gpflow/kernels/stationaries.py
+++ b/gpflow/kernels/stationaries.py
@@ -41,7 +41,7 @@
         :param variance: the (initial) value for the variance parameter.
         :param lengthscales: the (initial) value for the lengthscale
             parameter(s), to induce ARD behaviour this must be initialised as
-            an array the same length as the the number of active dimensions
+            an array the same length as the number of active dimensions
             e.g. [1., 1., 1.]. If only a single value is passed, this value
             is used as the lengthscale of each dimension.
         :param kwargs: accepts `name` and `active_dims`, which is a list or
@@ -122,6 +122,26 @@
     input dimension.
     """
 
+    def __init__(
+        self, variance: TensorType = 1.0, lengthscales: TensorType = 1.0, **kwargs: Any
+    ) -> None:
+        """
+        :param variance: the (initial) value for the variance parameter.
+        :param lengthscales: the (initial) value for the lengthscale
+            parameter(s), to induce ARD behaviour this must be initialised as
+            an array the same length as the number of active dimensions
+            e.g. [1., 1., 1.]. Note that anisotropic kernels can possess
+            negative lengthscales. If only a single value is passed, this
+            value is used as the lengthscale of each dimension.
+        :param kwargs: accepts `name` and `active_dims`, which is a list or
+            slice of indices which controls which columns of X are used (by
+            default, all columns are used).
+        """
+        super().__init__(variance, lengthscales, **kwargs)
+
+        if self.ard:
+            self.lengthscales = Parameter(self.lengthscales.numpy())
+
     def K(self, X: TensorType, X2: Optional[TensorType] = None) -> tf.Tensor:
         return self.K_d(self.scaled_difference_matrix(X, X2))

{"golden_diff": "diff --git a/gpflow/kernels/stationaries.py b/gpflow/kernels/stationaries.py\n--- a/gpflow/kernels/stationaries.py\n+++ b/gpflow/kernels/stationaries.py\n@@ -41,7 +41,7 @@\n         :param variance: the (initial) value for the variance parameter.\n         :param lengthscales: the (initial) value for the lengthscale\n             parameter(s), to induce ARD behaviour this must be initialised as\n-            an array the same length as the the number of active dimensions\n+            an array the same length as the number of active dimensions\n             e.g. [1., 1., 1.]. If only a single value is passed, this value\n             is used as the lengthscale of each dimension.\n         :param kwargs: accepts `name` and `active_dims`, which is a list or\n@@ -122,6 +122,26 @@\n     input dimension.\n     \"\"\"\n \n+    def __init__(\n+        self, variance: TensorType = 1.0, lengthscales: TensorType = 1.0, **kwargs: Any\n+    ) -> None:\n+        \"\"\"\n+        :param variance: the (initial) value for the variance parameter.\n+        :param lengthscales: the (initial) value for the lengthscale\n+            parameter(s), to induce ARD behaviour this must be initialised as\n+            an array the same length as the number of active dimensions\n+            e.g. [1., 1., 1.]. Note that anisotropic kernels can possess\n+            negative lengthscales. If only a single value is passed, this\n+            value is used as the lengthscale of each dimension.\n+        :param kwargs: accepts `name` and `active_dims`, which is a list or\n+            slice of indices which controls which columns of X are used (by\n+            default, all columns are used).\n+        \"\"\"\n+        super().__init__(variance, lengthscales, **kwargs)\n+\n+        if self.ard:\n+            self.lengthscales = Parameter(self.lengthscales.numpy())\n+\n     def K(self, X: TensorType, X2: Optional[TensorType] = None) -> tf.Tensor:\n         return self.K_d(self.scaled_difference_matrix(X, X2))\n", "issue": "Anisotropic lengthscales\nCurrently, by default, all stationary kernels impose a positive transform on the lengthscales Parameter. For the case of AnisotropicStationary kernels, this reduces the viable parameter space by a factor of 2^(D-1), where D is the number of input dimensions. So it is acceptable in the case of a 1D problem, but in higher dimensions we would miss out. For example, for the Cosine kernel there is a significant difference between lengthscales of [+1, +1], and [+1, -1], they correspond to waves propagating in perpendicular directions. \r\n\n", "before_files": [{"content": "# Copyright 2017-2020 The GPflow Contributors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom typing import Any, Optional\n\nimport numpy as np\nimport tensorflow as tf\n\nfrom ..base import Parameter, TensorType\nfrom ..utilities import positive\nfrom ..utilities.ops import difference_matrix, square_distance\nfrom .base import ActiveDims, Kernel\n\n\nclass Stationary(Kernel):\n    \"\"\"\n    Base class for kernels that are stationary, that is, they only depend on\n\n        d = x - x'\n\n    This class handles 'ard' behaviour, which stands for 'Automatic Relevance\n    Determination'. This means that the kernel has one lengthscale per\n    dimension, otherwise the kernel is isotropic (has a single lengthscale).\n    \"\"\"\n\n    def __init__(\n        self, variance: TensorType = 1.0, lengthscales: TensorType = 1.0, **kwargs: Any\n    ) -> None:\n        \"\"\"\n        :param variance: the (initial) value for the variance parameter.\n        :param lengthscales: the (initial) value for the lengthscale\n            parameter(s), to induce ARD behaviour this must be initialised as\n            an array the same length as the the number of active dimensions\n            e.g. [1., 1., 1.]. If only a single value is passed, this value\n            is used as the lengthscale of each dimension.\n        :param kwargs: accepts `name` and `active_dims`, which is a list or\n            slice of indices which controls which columns of X are used (by\n            default, all columns are used).\n        \"\"\"\n        for kwarg in kwargs:\n            if kwarg not in {\"name\", \"active_dims\"}:\n                raise TypeError(f\"Unknown keyword argument: {kwarg}\")\n\n        super().__init__(**kwargs)\n        self.variance = Parameter(variance, transform=positive())\n        self.lengthscales = Parameter(lengthscales, transform=positive())\n        self._validate_ard_active_dims(self.lengthscales)\n\n    @property\n    def ard(self) -> bool:\n        \"\"\"\n        Whether ARD behaviour is active.\n        \"\"\"\n        ndims: int = self.lengthscales.shape.ndims\n        return ndims > 0\n\n    def scale(self, X: TensorType) -> TensorType:\n        X_scaled = X / self.lengthscales if X is not None else X\n        return X_scaled\n\n    def K_diag(self, X: TensorType) -> tf.Tensor:\n        return tf.fill(tf.shape(X)[:-1], tf.squeeze(self.variance))\n\n\nclass IsotropicStationary(Stationary):\n    \"\"\"\n    Base class for isotropic stationary kernels, i.e. kernels that only\n    depend on\n\n        r = \u2016x - x'\u2016\n\n    Derived classes should implement one of:\n\n        K_r2(self, r2): Returns the kernel evaluated on r\u00b2 (r2), which is the\n        squared scaled Euclidean distance Should operate element-wise on r2.\n\n        K_r(self, r): Returns the kernel evaluated on r, which is the scaled\n        Euclidean distance. Should operate element-wise on r.\n    \"\"\"\n\n    def K(self, X: TensorType, X2: Optional[TensorType] = None) -> tf.Tensor:\n        r2 = self.scaled_squared_euclid_dist(X, X2)\n        return self.K_r2(r2)\n\n    def K_r2(self, r2: TensorType) -> tf.Tensor:\n        if hasattr(self, \"K_r\"):\n            # Clipping around the (single) float precision which is ~1e-45.\n            r = tf.sqrt(tf.maximum(r2, 1e-36))\n            return self.K_r(r)  # pylint: disable=no-member\n        raise NotImplementedError\n\n    def scaled_squared_euclid_dist(\n        self, X: TensorType, X2: Optional[TensorType] = None\n    ) -> tf.Tensor:\n        \"\"\"\n        Returns \u2016(X - X2\u1d40) / \u2113\u2016\u00b2, i.e. the squared L\u2082-norm.\n        \"\"\"\n        return square_distance(self.scale(X), self.scale(X2))\n\n\nclass AnisotropicStationary(Stationary):\n    \"\"\"\n    Base class for anisotropic stationary kernels, i.e. kernels that only\n    depend on\n\n        d = x - x'\n\n    Derived classes should implement K_d(self, d): Returns the kernel evaluated\n    on d, which is the pairwise difference matrix, scaled by the lengthscale\n    parameter \u2113 (i.e. [(X - X2\u1d40) / \u2113]). The last axis corresponds to the\n    input dimension.\n    \"\"\"\n\n    def K(self, X: TensorType, X2: Optional[TensorType] = None) -> tf.Tensor:\n        return self.K_d(self.scaled_difference_matrix(X, X2))\n\n    def scaled_difference_matrix(self, X: TensorType, X2: Optional[TensorType] = None) -> tf.Tensor:\n        \"\"\"\n        Returns [(X - X2\u1d40) / \u2113]. If X has shape [..., N, D] and\n        X2 has shape [..., M, D], the output will have shape [..., N, M, D].\n        \"\"\"\n        return difference_matrix(self.scale(X), self.scale(X2))\n\n    def K_d(self, d: TensorType) -> tf.Tensor:\n        raise NotImplementedError\n\n\nclass SquaredExponential(IsotropicStationary):\n    \"\"\"\n    The radial basis function (RBF) or squared exponential kernel. The kernel equation is\n\n        k(r) = \u03c3\u00b2 exp{-\u00bd r\u00b2}\n\n    where:\n    r   is the Euclidean distance between the input points, scaled by the lengthscales parameter \u2113.\n    \u03c3\u00b2  is the variance parameter\n\n    Functions drawn from a GP with this kernel are infinitely differentiable!\n    \"\"\"\n\n    def K_r2(self, r2: TensorType) -> tf.Tensor:\n        return self.variance * tf.exp(-0.5 * r2)\n\n\nclass RationalQuadratic(IsotropicStationary):\n    \"\"\"\n    Rational Quadratic kernel,\n\n    k(r) = \u03c3\u00b2 (1 + r\u00b2 / 2\u03b1\u2113\u00b2)^(-\u03b1)\n\n    \u03c3\u00b2 : variance\n    \u2113  : lengthscales\n    \u03b1  : alpha, determines relative weighting of small-scale and large-scale fluctuations\n\n    For \u03b1 \u2192 \u221e, the RQ kernel becomes equivalent to the squared exponential.\n    \"\"\"\n\n    def __init__(\n        self,\n        variance: TensorType = 1.0,\n        lengthscales: TensorType = 1.0,\n        alpha: TensorType = 1.0,\n        active_dims: Optional[ActiveDims] = None,\n    ) -> None:\n        super().__init__(variance=variance, lengthscales=lengthscales, active_dims=active_dims)\n        self.alpha = Parameter(alpha, transform=positive())\n\n    def K_r2(self, r2: TensorType) -> tf.Tensor:\n        return self.variance * (1 + 0.5 * r2 / self.alpha) ** (-self.alpha)\n\n\nclass Exponential(IsotropicStationary):\n    \"\"\"\n    The Exponential kernel. It is equivalent to a Matern12 kernel with doubled lengthscales.\n    \"\"\"\n\n    def K_r(self, r: TensorType) -> tf.Tensor:\n        return self.variance * tf.exp(-0.5 * r)\n\n\nclass Matern12(IsotropicStationary):\n    \"\"\"\n    The Matern 1/2 kernel. Functions drawn from a GP with this kernel are not\n    differentiable anywhere. The kernel equation is\n\n    k(r) = \u03c3\u00b2 exp{-r}\n\n    where:\n    r  is the Euclidean distance between the input points, scaled by the lengthscales parameter \u2113.\n    \u03c3\u00b2 is the variance parameter\n    \"\"\"\n\n    def K_r(self, r: TensorType) -> tf.Tensor:\n        return self.variance * tf.exp(-r)\n\n\nclass Matern32(IsotropicStationary):\n    \"\"\"\n    The Matern 3/2 kernel. Functions drawn from a GP with this kernel are once\n    differentiable. The kernel equation is\n\n    k(r) = \u03c3\u00b2 (1 + \u221a3r) exp{-\u221a3 r}\n\n    where:\n    r  is the Euclidean distance between the input points, scaled by the lengthscales parameter \u2113,\n    \u03c3\u00b2 is the variance parameter.\n    \"\"\"\n\n    def K_r(self, r: TensorType) -> tf.Tensor:\n        sqrt3 = np.sqrt(3.0)\n        return self.variance * (1.0 + sqrt3 * r) * tf.exp(-sqrt3 * r)\n\n\nclass Matern52(IsotropicStationary):\n    \"\"\"\n    The Matern 5/2 kernel. Functions drawn from a GP with this kernel are twice\n    differentiable. The kernel equation is\n\n    k(r) = \u03c3\u00b2 (1 + \u221a5r + 5/3r\u00b2) exp{-\u221a5 r}\n\n    where:\n    r  is the Euclidean distance between the input points, scaled by the lengthscales parameter \u2113,\n    \u03c3\u00b2 is the variance parameter.\n    \"\"\"\n\n    def K_r(self, r: TensorType) -> tf.Tensor:\n        sqrt5 = np.sqrt(5.0)\n        return self.variance * (1.0 + sqrt5 * r + 5.0 / 3.0 * tf.square(r)) * tf.exp(-sqrt5 * r)\n\n\nclass Cosine(AnisotropicStationary):\n    \"\"\"\n    The Cosine kernel. Functions drawn from a GP with this kernel are sinusoids\n    (with a random phase).  The kernel equation is\n\n        k(r) = \u03c3\u00b2 cos{2\u03c0d}\n\n    where:\n    d  is the sum of the per-dimension differences between the input points, scaled by the\n    lengthscale parameter \u2113 (i.e. \u03a3\u1d62 [(X - X2\u1d40) / \u2113]\u1d62),\n    \u03c3\u00b2 is the variance parameter.\n    \"\"\"\n\n    def K_d(self, d: TensorType) -> tf.Tensor:\n        d = tf.reduce_sum(d, axis=-1)\n        return self.variance * tf.cos(2 * np.pi * d)\n", "path": "gpflow/kernels/stationaries.py"}], "after_files": [{"content": "# Copyright 2017-2020 The GPflow Contributors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom typing import Any, Optional\n\nimport numpy as np\nimport tensorflow as tf\n\nfrom ..base import Parameter, TensorType\nfrom ..utilities import positive\nfrom ..utilities.ops import difference_matrix, square_distance\nfrom .base import ActiveDims, Kernel\n\n\nclass Stationary(Kernel):\n    \"\"\"\n    Base class for kernels that are stationary, that is, they only depend on\n\n        d = x - x'\n\n    This class handles 'ard' behaviour, which stands for 'Automatic Relevance\n    Determination'. This means that the kernel has one lengthscale per\n    dimension, otherwise the kernel is isotropic (has a single lengthscale).\n    \"\"\"\n\n    def __init__(\n        self, variance: TensorType = 1.0, lengthscales: TensorType = 1.0, **kwargs: Any\n    ) -> None:\n        \"\"\"\n        :param variance: the (initial) value for the variance parameter.\n        :param lengthscales: the (initial) value for the lengthscale\n            parameter(s), to induce ARD behaviour this must be initialised as\n            an array the same length as the number of active dimensions\n            e.g. [1., 1., 1.]. If only a single value is passed, this value\n            is used as the lengthscale of each dimension.\n        :param kwargs: accepts `name` and `active_dims`, which is a list or\n            slice of indices which controls which columns of X are used (by\n            default, all columns are used).\n        \"\"\"\n        for kwarg in kwargs:\n            if kwarg not in {\"name\", \"active_dims\"}:\n                raise TypeError(f\"Unknown keyword argument: {kwarg}\")\n\n        super().__init__(**kwargs)\n        self.variance = Parameter(variance, transform=positive())\n        self.lengthscales = Parameter(lengthscales, transform=positive())\n        self._validate_ard_active_dims(self.lengthscales)\n\n    @property\n    def ard(self) -> bool:\n        \"\"\"\n        Whether ARD behaviour is active.\n        \"\"\"\n        ndims: int = self.lengthscales.shape.ndims\n        return ndims > 0\n\n    def scale(self, X: TensorType) -> TensorType:\n        X_scaled = X / self.lengthscales if X is not None else X\n        return X_scaled\n\n    def K_diag(self, X: TensorType) -> tf.Tensor:\n        return tf.fill(tf.shape(X)[:-1], tf.squeeze(self.variance))\n\n\nclass IsotropicStationary(Stationary):\n    \"\"\"\n    Base class for isotropic stationary kernels, i.e. kernels that only\n    depend on\n\n        r = \u2016x - x'\u2016\n\n    Derived classes should implement one of:\n\n        K_r2(self, r2): Returns the kernel evaluated on r\u00b2 (r2), which is the\n        squared scaled Euclidean distance Should operate element-wise on r2.\n\n        K_r(self, r): Returns the kernel evaluated on r, which is the scaled\n        Euclidean distance. Should operate element-wise on r.\n    \"\"\"\n\n    def K(self, X: TensorType, X2: Optional[TensorType] = None) -> tf.Tensor:\n        r2 = self.scaled_squared_euclid_dist(X, X2)\n        return self.K_r2(r2)\n\n    def K_r2(self, r2: TensorType) -> tf.Tensor:\n        if hasattr(self, \"K_r\"):\n            # Clipping around the (single) float precision which is ~1e-45.\n            r = tf.sqrt(tf.maximum(r2, 1e-36))\n            return self.K_r(r)  # pylint: disable=no-member\n        raise NotImplementedError\n\n    def scaled_squared_euclid_dist(\n        self, X: TensorType, X2: Optional[TensorType] = None\n    ) -> tf.Tensor:\n        \"\"\"\n        Returns \u2016(X - X2\u1d40) / \u2113\u2016\u00b2, i.e. the squared L\u2082-norm.\n        \"\"\"\n        return square_distance(self.scale(X), self.scale(X2))\n\n\nclass AnisotropicStationary(Stationary):\n    \"\"\"\n    Base class for anisotropic stationary kernels, i.e. kernels that only\n    depend on\n\n        d = x - x'\n\n    Derived classes should implement K_d(self, d): Returns the kernel evaluated\n    on d, which is the pairwise difference matrix, scaled by the lengthscale\n    parameter \u2113 (i.e. [(X - X2\u1d40) / \u2113]). The last axis corresponds to the\n    input dimension.\n    \"\"\"\n\n    def __init__(\n        self, variance: TensorType = 1.0, lengthscales: TensorType = 1.0, **kwargs: Any\n    ) -> None:\n        \"\"\"\n        :param variance: the (initial) value for the variance parameter.\n        :param lengthscales: the (initial) value for the lengthscale\n            parameter(s), to induce ARD behaviour this must be initialised as\n            an array the same length as the number of active dimensions\n            e.g. [1., 1., 1.]. Note that anisotropic kernels can possess\n            negative lengthscales. If only a single value is passed, this\n            value is used as the lengthscale of each dimension.\n        :param kwargs: accepts `name` and `active_dims`, which is a list or\n            slice of indices which controls which columns of X are used (by\n            default, all columns are used).\n        \"\"\"\n        super().__init__(variance, lengthscales, **kwargs)\n\n        if self.ard:\n            self.lengthscales = Parameter(self.lengthscales.numpy())\n\n    def K(self, X: TensorType, X2: Optional[TensorType] = None) -> tf.Tensor:\n        return self.K_d(self.scaled_difference_matrix(X, X2))\n\n    def scaled_difference_matrix(self, X: TensorType, X2: Optional[TensorType] = None) -> tf.Tensor:\n        \"\"\"\n        Returns [(X - X2\u1d40) / \u2113]. If X has shape [..., N, D] and\n        X2 has shape [..., M, D], the output will have shape [..., N, M, D].\n        \"\"\"\n        return difference_matrix(self.scale(X), self.scale(X2))\n\n    def K_d(self, d: TensorType) -> tf.Tensor:\n        raise NotImplementedError\n\n\nclass SquaredExponential(IsotropicStationary):\n    \"\"\"\n    The radial basis function (RBF) or squared exponential kernel. The kernel equation is\n\n        k(r) = \u03c3\u00b2 exp{-\u00bd r\u00b2}\n\n    where:\n    r   is the Euclidean distance between the input points, scaled by the lengthscales parameter \u2113.\n    \u03c3\u00b2  is the variance parameter\n\n    Functions drawn from a GP with this kernel are infinitely differentiable!\n    \"\"\"\n\n    def K_r2(self, r2: TensorType) -> tf.Tensor:\n        return self.variance * tf.exp(-0.5 * r2)\n\n\nclass RationalQuadratic(IsotropicStationary):\n    \"\"\"\n    Rational Quadratic kernel,\n\n    k(r) = \u03c3\u00b2 (1 + r\u00b2 / 2\u03b1\u2113\u00b2)^(-\u03b1)\n\n    \u03c3\u00b2 : variance\n    \u2113  : lengthscales\n    \u03b1  : alpha, determines relative weighting of small-scale and large-scale fluctuations\n\n    For \u03b1 \u2192 \u221e, the RQ kernel becomes equivalent to the squared exponential.\n    \"\"\"\n\n    def __init__(\n        self,\n        variance: TensorType = 1.0,\n        lengthscales: TensorType = 1.0,\n        alpha: TensorType = 1.0,\n        active_dims: Optional[ActiveDims] = None,\n    ) -> None:\n        super().__init__(variance=variance, lengthscales=lengthscales, active_dims=active_dims)\n        self.alpha = Parameter(alpha, transform=positive())\n\n    def K_r2(self, r2: TensorType) -> tf.Tensor:\n        return self.variance * (1 + 0.5 * r2 / self.alpha) ** (-self.alpha)\n\n\nclass Exponential(IsotropicStationary):\n    \"\"\"\n    The Exponential kernel. It is equivalent to a Matern12 kernel with doubled lengthscales.\n    \"\"\"\n\n    def K_r(self, r: TensorType) -> tf.Tensor:\n        return self.variance * tf.exp(-0.5 * r)\n\n\nclass Matern12(IsotropicStationary):\n    \"\"\"\n    The Matern 1/2 kernel. Functions drawn from a GP with this kernel are not\n    differentiable anywhere. The kernel equation is\n\n    k(r) = \u03c3\u00b2 exp{-r}\n\n    where:\n    r  is the Euclidean distance between the input points, scaled by the lengthscales parameter \u2113.\n    \u03c3\u00b2 is the variance parameter\n    \"\"\"\n\n    def K_r(self, r: TensorType) -> tf.Tensor:\n        return self.variance * tf.exp(-r)\n\n\nclass Matern32(IsotropicStationary):\n    \"\"\"\n    The Matern 3/2 kernel. Functions drawn from a GP with this kernel are once\n    differentiable. The kernel equation is\n\n    k(r) = \u03c3\u00b2 (1 + \u221a3r) exp{-\u221a3 r}\n\n    where:\n    r  is the Euclidean distance between the input points, scaled by the lengthscales parameter \u2113,\n    \u03c3\u00b2 is the variance parameter.\n    \"\"\"\n\n    def K_r(self, r: TensorType) -> tf.Tensor:\n        sqrt3 = np.sqrt(3.0)\n        return self.variance * (1.0 + sqrt3 * r) * tf.exp(-sqrt3 * r)\n\n\nclass Matern52(IsotropicStationary):\n    \"\"\"\n    The Matern 5/2 kernel. Functions drawn from a GP with this kernel are twice\n    differentiable. The kernel equation is\n\n    k(r) = \u03c3\u00b2 (1 + \u221a5r + 5/3r\u00b2) exp{-\u221a5 r}\n\n    where:\n    r  is the Euclidean distance between the input points, scaled by the lengthscales parameter \u2113,\n    \u03c3\u00b2 is the variance parameter.\n    \"\"\"\n\n    def K_r(self, r: TensorType) -> tf.Tensor:\n        sqrt5 = np.sqrt(5.0)\n        return self.variance * (1.0 + sqrt5 * r + 5.0 / 3.0 * tf.square(r)) * tf.exp(-sqrt5 * r)\n\n\nclass Cosine(AnisotropicStationary):\n    \"\"\"\n    The Cosine kernel. Functions drawn from a GP with this kernel are sinusoids\n    (with a random phase).  The kernel equation is\n\n        k(r) = \u03c3\u00b2 cos{2\u03c0d}\n\n    where:\n    d  is the sum of the per-dimension differences between the input points, scaled by the\n    lengthscale parameter \u2113 (i.e. \u03a3\u1d62 [(X - X2\u1d40) / \u2113]\u1d62),\n    \u03c3\u00b2 is the variance parameter.\n    \"\"\"\n\n    def K_d(self, d: TensorType) -> tf.Tensor:\n        d = tf.reduce_sum(d, axis=-1)\n        return self.variance * tf.cos(2 * np.pi * d)\n", "path": "gpflow/kernels/stationaries.py"}]}