We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Positive transform fails large numbers
The positive transform implemented in `GPflow.transforms.positive` is an alias for the `Log1pe`-transform. The name suggests that it can be used to represent arbitrary positive numbers, however, it is actually only possible to to represent numbers up a value of about 700 due to the result of `np.exp` growing too large:

```python
In [31]: GPflow.transforms.positive.forward(700)
Out[31]: 700.000001

In [32]: GPflow.transforms.positive.forward(800)
/(...)/GPflow/transforms.py:129: RuntimeWarning: overflow encountered in exp
  return np.log(1. + np.exp(x)) + self._lower
Out[32]: inf

In [33]: GPflow.transforms.positive.backward(700)
Out[33]: array([ 699.999999])

In [34]: GPflow.transforms.positive.backward(800)
/(...)/GPflow/transforms.py:138: RuntimeWarning: overflow encountered in exp
  return np.log(np.exp(y - self._lower) - np.ones(1, np_float_type))
Out[34]: array([ inf])
```

Since the positive transform degrades to an identity function for large values, it should be fairly easy to fix this. However, it is probably important to ensure that both `forward` and `tf_forward` behave the same.

I guess a similar problem will exist for the `Logistic`-transform.

--- 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/transforms.py`
Content:
```
1 # Copyright 2016 James Hensman, alexggmatthews
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 __future__ import absolute_import
16 import numpy as np
17 import tensorflow as tf
18 from . import tf_wraps as tfw
19 from ._settings import settings
20 
21 float_type = settings.dtypes.float_type
22 np_float_type = np.float32 if float_type is tf.float32 else np.float64
23 
24 
25 class Transform(object):
26     def forward(self, x):
27         """
28         Map from the free-space to the variable space, using numpy
29         """
30         raise NotImplementedError
31 
32     def backward(self, y):
33         """
34         Map from the variable-space to the free space, using numpy
35         """
36         raise NotImplementedError
37 
38     def tf_forward(self, x):
39         """
40         Map from the free-space to the variable space, using tensorflow
41         """
42         raise NotImplementedError
43 
44     def tf_log_jacobian(self, x):
45         """
46         Return the log Jacobian of the tf_forward mapping.
47 
48         Note that we *could* do this using a tf manipulation of
49         self.tf_forward, but tensorflow may have difficulty: it doesn't have a
50         Jacaobian at time of writing.  We do this in the tests to make sure the
51         implementation is correct.
52         """
53         raise NotImplementedError
54 
55     def free_state_size(self, variable_shape):
56         return np.prod(variable_shape)
57 
58     def __str__(self):
59         """
60         A short string describing the nature of the constraint
61         """
62         raise NotImplementedError
63 
64     def __getstate__(self):
65         return self.__dict__.copy()
66 
67     def __setstate__(self, d):
68         self.__dict__ = d
69 
70 
71 class Identity(Transform):
72     def tf_forward(self, x):
73         return tf.identity(x)
74 
75     def forward(self, x):
76         return x
77 
78     def backward(self, y):
79         return y
80 
81     def tf_log_jacobian(self, x):
82         return tf.zeros((1,), float_type)
83 
84     def __str__(self):
85         return '(none)'
86 
87 
88 class Exp(Transform):
89     def __init__(self, lower=1e-6):
90         self._lower = lower
91 
92     def tf_forward(self, x):
93         return tf.exp(x) + self._lower
94 
95     def forward(self, x):
96         return np.exp(x) + self._lower
97 
98     def backward(self, y):
99         return np.log(y - self._lower)
100 
101     def tf_log_jacobian(self, x):
102         return tf.reduce_sum(x)
103 
104     def __str__(self):
105         return '+ve'
106 
107 
108 class Log1pe(Transform):
109     """
110     A transform of the form
111 
112        y = \log ( 1 + \exp(x))
113 
114     x is a free variable, y is always positive.
115 
116     This function is known as 'softplus' in tensorflow.
117     """
118 
119     def __init__(self, lower=1e-6):
120         """
121         lower is a float that defines the minimum value that this transform can
122         take, default 1e-6. This helps stability during optimization, because
123         aggressive optimizers can take overly-long steps which lead to zero in
124         the transformed variable, causing an error.
125         """
126         self._lower = lower
127 
128     def forward(self, x):
129         return np.log(1. + np.exp(x)) + self._lower
130 
131     def tf_forward(self, x):
132         return tf.nn.softplus(x) + self._lower
133 
134     def tf_log_jacobian(self, x):
135         return -tf.reduce_sum(tf.log(1. + tf.exp(-x)))
136 
137     def backward(self, y):
138         return np.log(np.exp(y - self._lower) - np.ones(1, np_float_type))
139 
140     def __str__(self):
141         return '+ve'
142 
143 
144 class Logistic(Transform):
145     def __init__(self, a=0., b=1.):
146         Transform.__init__(self)
147         assert b > a
148         self.a, self.b = float(a), float(b)
149 
150     def tf_forward(self, x):
151         ex = tf.exp(-x)
152         return self.a + (self.b - self.a) / (1. + ex)
153 
154     def forward(self, x):
155         ex = np.exp(-x)
156         return self.a + (self.b - self.a) / (1. + ex)
157 
158     def backward(self, y):
159         return -np.log((self.b - self.a) / (y - self.a) - 1.)
160 
161     def tf_log_jacobian(self, x):
162         return tf.reduce_sum(x - 2. * tf.log(tf.exp(x) + 1.) + np.log(self.b - self.a))
163 
164     def __str__(self):
165         return '[' + str(self.a) + ', ' + str(self.b) + ']'
166 
167 
168 class DiagMatrix(Transform):
169     """
170     A transform to represent diagonal matrices.
171 
172     The output of this transform is a N x dim x dim array of diagonal matrices.
173     The contructor argumnet dim specifies the size of the matrixes.
174 
175     Additionally, to ensure that the matrices are positive definite, the
176     diagonal elements are pushed through a 'positive' transform, defaulting to
177     log1pe.
178     """
179     def __init__(self, dim=1, positive_transform=Log1pe()):
180         self.dim = dim
181         self._lower = 1e-6
182         self._positive_transform = positive_transform
183 
184     def forward(self, x):
185         # Create diagonal matrix
186         x = self._positive_transform.forward(x).reshape((-1, self.dim))
187         m = np.zeros((x.shape[0], x.shape[1], x.shape[1]))
188         m[(np.s_[:],) + np.diag_indices(x.shape[1])] = x
189         return m
190 
191     def backward(self, y):
192         # Return diagonals of matrices
193         return self._positive_transform.backward(y.reshape(-1, self.dim, self.dim).diagonal(0, 1, 2).flatten())
194 
195     def tf_forward(self, x):
196         return tf.matrix_diag(tf.reshape(self._positive_transform.tf_forward(x), (-1, self.dim)))
197 
198     def tf_log_jacobian(self, x):
199         return tf.zeros((1,), float_type) + self._positive_transform.tf_log_jacobian(x)
200 
201     def __str__(self):
202         return 'DiagMatrix'
203 
204     def free_state_size(self, variable_shape):
205         return variable_shape[0] * variable_shape[1]
206 
207 
208 class LowerTriangular(Transform):
209     """
210     A transform of the form
211 
212        tri_mat = vec_to_tri(x)
213 
214     x is a free variable, y is always a list of lower triangular matrices sized
215     (N x N x D).
216     """
217 
218     def __init__(self, num_matrices=1, squeeze=False):
219         """
220         Create an instance of LowerTriangular transform.
221         Args:
222             num_matrices: Number of matrices to be stored.
223             squeeze: If num_matrices == 1, drop the redundant axis.
224         """
225         self.num_matrices = num_matrices  # We need to store this for reconstruction.
226         self.squeeze = squeeze
227 
228     def _validate_vector_length(self, length):
229         """
230         Check whether the vector length is consistent with being a triangular
231          matrix and with `self.num_matrices`.
232         Args:
233             length: Length of the free state vector.
234 
235         Returns: Length of the vector with the lower triangular elements.
236 
237         """
238         L = length / self.num_matrices
239         if int(((L * 8) + 1) ** 0.5) ** 2.0 != (L * 8 + 1):
240             raise ValueError("The free state must be a triangle number.")
241         return L
242 
243     def forward(self, x):
244         """
245         Transforms from the free state to the variable.
246         Args:
247             x: Free state vector. Must have length of `self.num_matrices` *
248                 triangular_number.
249 
250         Returns:
251             Reconstructed variable.
252         """
253         L = self._validate_vector_length(len(x))
254         matsize = int((L * 8 + 1) ** 0.5 * 0.5 - 0.5)
255         xr = np.reshape(x, (self.num_matrices, -1))
256         var = np.zeros((matsize, matsize, self.num_matrices), np_float_type)
257         for i in range(self.num_matrices):
258             indices = np.tril_indices(matsize, 0)
259             var[indices + (np.zeros(len(indices[0])).astype(int) + i,)] = xr[i, :]
260         return var.squeeze() if self.squeeze else var
261 
262     def backward(self, y):
263         """
264         Transforms from the variable to the free state.
265         Args:
266             y: Variable representation.
267 
268         Returns:
269             Free state.
270         """
271         N = int((y.size / self.num_matrices) ** 0.5)
272         y = np.reshape(y, (N, N, self.num_matrices))
273         return y[np.tril_indices(len(y), 0)].T.flatten()
274 
275     def tf_forward(self, x):
276         fwd = tf.transpose(tfw.vec_to_tri(tf.reshape(x, (self.num_matrices, -1))), [1, 2, 0])
277         return tf.squeeze(fwd) if self.squeeze else fwd
278 
279     def tf_log_jacobian(self, x):
280         return tf.zeros((1,), float_type)
281 
282     def free_state_size(self, variable_shape):
283         matrix_batch = len(variable_shape) > 2
284         if ((not matrix_batch and self.num_matrices != 1) or
285                 (matrix_batch and variable_shape[2] != self.num_matrices)):
286             raise ValueError("Number of matrices must be consistent with what was passed to the constructor.")
287         if variable_shape[0] != variable_shape[1]:
288             raise ValueError("Matrices passed must be square.")
289         N = variable_shape[0]
290         return int(0.5 * N * (N + 1)) * (variable_shape[2] if matrix_batch else 1)
291 
292     def __str__(self):
293         return "LoTri->vec"
294 
295 
296 positive = Log1pe()
297
```
--- 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/transforms.py b/GPflow/transforms.py
--- a/GPflow/transforms.py
+++ b/GPflow/transforms.py
@@ -126,7 +126,9 @@
         self._lower = lower
 
     def forward(self, x):
-        return np.log(1. + np.exp(x)) + self._lower
+        result = np.log(1. + np.exp(x)) + self._lower
+        # do not transform large numbers, they overflow and the mapping is exactly identity.
+        return np.where(x > 35, x + self._lower, result)
 
     def tf_forward(self, x):
         return tf.nn.softplus(x) + self._lower
@@ -135,7 +137,8 @@
         return -tf.reduce_sum(tf.log(1. + tf.exp(-x)))
 
     def backward(self, y):
-        return np.log(np.exp(y - self._lower) - np.ones(1, np_float_type))
+        result = np.log(np.exp(y - self._lower) - np.ones(1, np_float_type))
+        return np.where(y > 35, y-self._lower, result)
 
     def __str__(self):
         return '+ve'

{"golden_diff": "diff --git a/GPflow/transforms.py b/GPflow/transforms.py\n--- a/GPflow/transforms.py\n+++ b/GPflow/transforms.py\n@@ -126,7 +126,9 @@\n         self._lower = lower\n \n     def forward(self, x):\n-        return np.log(1. + np.exp(x)) + self._lower\n+        result = np.log(1. + np.exp(x)) + self._lower\n+        # do not transform large numbers, they overflow and the mapping is exactly identity.\n+        return np.where(x > 35, x + self._lower, result)\n \n     def tf_forward(self, x):\n         return tf.nn.softplus(x) + self._lower\n@@ -135,7 +137,8 @@\n         return -tf.reduce_sum(tf.log(1. + tf.exp(-x)))\n \n     def backward(self, y):\n-        return np.log(np.exp(y - self._lower) - np.ones(1, np_float_type))\n+        result = np.log(np.exp(y - self._lower) - np.ones(1, np_float_type))\n+        return np.where(y > 35, y-self._lower, result)\n \n     def __str__(self):\n         return '+ve'\n", "issue": "Positive transform fails large numbers\nThe positive transform implemented in `GPflow.transforms.positive` is an alias for the `Log1pe`-transform. The name suggests that it can be used to represent arbitrary positive numbers, however, it is actually only possible to to represent numbers up a value of about 700 due to the result of `np.exp` growing too large:\r\n\r\n```python\r\nIn [31]: GPflow.transforms.positive.forward(700)\r\nOut[31]: 700.000001\r\n\r\nIn [32]: GPflow.transforms.positive.forward(800)\r\n/(...)/GPflow/transforms.py:129: RuntimeWarning: overflow encountered in exp\r\n  return np.log(1. + np.exp(x)) + self._lower\r\nOut[32]: inf\r\n\r\nIn [33]: GPflow.transforms.positive.backward(700)\r\nOut[33]: array([ 699.999999])\r\n\r\nIn [34]: GPflow.transforms.positive.backward(800)\r\n/(...)/GPflow/transforms.py:138: RuntimeWarning: overflow encountered in exp\r\n  return np.log(np.exp(y - self._lower) - np.ones(1, np_float_type))\r\nOut[34]: array([ inf])\r\n```\r\n\r\nSince the positive transform degrades to an identity function for large values, it should be fairly easy to fix this. However, it is probably important to ensure that both `forward` and `tf_forward` behave the same.\r\n\r\nI guess a similar problem will exist for the `Logistic`-transform.\n", "before_files": [{"content": "# Copyright 2016 James Hensman, alexggmatthews\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 __future__ import absolute_import\nimport numpy as np\nimport tensorflow as tf\nfrom . import tf_wraps as tfw\nfrom ._settings import settings\n\nfloat_type = settings.dtypes.float_type\nnp_float_type = np.float32 if float_type is tf.float32 else np.float64\n\n\nclass Transform(object):\n    def forward(self, x):\n        \"\"\"\n        Map from the free-space to the variable space, using numpy\n        \"\"\"\n        raise NotImplementedError\n\n    def backward(self, y):\n        \"\"\"\n        Map from the variable-space to the free space, using numpy\n        \"\"\"\n        raise NotImplementedError\n\n    def tf_forward(self, x):\n        \"\"\"\n        Map from the free-space to the variable space, using tensorflow\n        \"\"\"\n        raise NotImplementedError\n\n    def tf_log_jacobian(self, x):\n        \"\"\"\n        Return the log Jacobian of the tf_forward mapping.\n\n        Note that we *could* do this using a tf manipulation of\n        self.tf_forward, but tensorflow may have difficulty: it doesn't have a\n        Jacaobian at time of writing.  We do this in the tests to make sure the\n        implementation is correct.\n        \"\"\"\n        raise NotImplementedError\n\n    def free_state_size(self, variable_shape):\n        return np.prod(variable_shape)\n\n    def __str__(self):\n        \"\"\"\n        A short string describing the nature of the constraint\n        \"\"\"\n        raise NotImplementedError\n\n    def __getstate__(self):\n        return self.__dict__.copy()\n\n    def __setstate__(self, d):\n        self.__dict__ = d\n\n\nclass Identity(Transform):\n    def tf_forward(self, x):\n        return tf.identity(x)\n\n    def forward(self, x):\n        return x\n\n    def backward(self, y):\n        return y\n\n    def tf_log_jacobian(self, x):\n        return tf.zeros((1,), float_type)\n\n    def __str__(self):\n        return '(none)'\n\n\nclass Exp(Transform):\n    def __init__(self, lower=1e-6):\n        self._lower = lower\n\n    def tf_forward(self, x):\n        return tf.exp(x) + self._lower\n\n    def forward(self, x):\n        return np.exp(x) + self._lower\n\n    def backward(self, y):\n        return np.log(y - self._lower)\n\n    def tf_log_jacobian(self, x):\n        return tf.reduce_sum(x)\n\n    def __str__(self):\n        return '+ve'\n\n\nclass Log1pe(Transform):\n    \"\"\"\n    A transform of the form\n\n       y = \\log ( 1 + \\exp(x))\n\n    x is a free variable, y is always positive.\n\n    This function is known as 'softplus' in tensorflow.\n    \"\"\"\n\n    def __init__(self, lower=1e-6):\n        \"\"\"\n        lower is a float that defines the minimum value that this transform can\n        take, default 1e-6. This helps stability during optimization, because\n        aggressive optimizers can take overly-long steps which lead to zero in\n        the transformed variable, causing an error.\n        \"\"\"\n        self._lower = lower\n\n    def forward(self, x):\n        return np.log(1. + np.exp(x)) + self._lower\n\n    def tf_forward(self, x):\n        return tf.nn.softplus(x) + self._lower\n\n    def tf_log_jacobian(self, x):\n        return -tf.reduce_sum(tf.log(1. + tf.exp(-x)))\n\n    def backward(self, y):\n        return np.log(np.exp(y - self._lower) - np.ones(1, np_float_type))\n\n    def __str__(self):\n        return '+ve'\n\n\nclass Logistic(Transform):\n    def __init__(self, a=0., b=1.):\n        Transform.__init__(self)\n        assert b > a\n        self.a, self.b = float(a), float(b)\n\n    def tf_forward(self, x):\n        ex = tf.exp(-x)\n        return self.a + (self.b - self.a) / (1. + ex)\n\n    def forward(self, x):\n        ex = np.exp(-x)\n        return self.a + (self.b - self.a) / (1. + ex)\n\n    def backward(self, y):\n        return -np.log((self.b - self.a) / (y - self.a) - 1.)\n\n    def tf_log_jacobian(self, x):\n        return tf.reduce_sum(x - 2. * tf.log(tf.exp(x) + 1.) + np.log(self.b - self.a))\n\n    def __str__(self):\n        return '[' + str(self.a) + ', ' + str(self.b) + ']'\n\n\nclass DiagMatrix(Transform):\n    \"\"\"\n    A transform to represent diagonal matrices.\n\n    The output of this transform is a N x dim x dim array of diagonal matrices.\n    The contructor argumnet dim specifies the size of the matrixes.\n\n    Additionally, to ensure that the matrices are positive definite, the\n    diagonal elements are pushed through a 'positive' transform, defaulting to\n    log1pe.\n    \"\"\"\n    def __init__(self, dim=1, positive_transform=Log1pe()):\n        self.dim = dim\n        self._lower = 1e-6\n        self._positive_transform = positive_transform\n\n    def forward(self, x):\n        # Create diagonal matrix\n        x = self._positive_transform.forward(x).reshape((-1, self.dim))\n        m = np.zeros((x.shape[0], x.shape[1], x.shape[1]))\n        m[(np.s_[:],) + np.diag_indices(x.shape[1])] = x\n        return m\n\n    def backward(self, y):\n        # Return diagonals of matrices\n        return self._positive_transform.backward(y.reshape(-1, self.dim, self.dim).diagonal(0, 1, 2).flatten())\n\n    def tf_forward(self, x):\n        return tf.matrix_diag(tf.reshape(self._positive_transform.tf_forward(x), (-1, self.dim)))\n\n    def tf_log_jacobian(self, x):\n        return tf.zeros((1,), float_type) + self._positive_transform.tf_log_jacobian(x)\n\n    def __str__(self):\n        return 'DiagMatrix'\n\n    def free_state_size(self, variable_shape):\n        return variable_shape[0] * variable_shape[1]\n\n\nclass LowerTriangular(Transform):\n    \"\"\"\n    A transform of the form\n\n       tri_mat = vec_to_tri(x)\n\n    x is a free variable, y is always a list of lower triangular matrices sized\n    (N x N x D).\n    \"\"\"\n\n    def __init__(self, num_matrices=1, squeeze=False):\n        \"\"\"\n        Create an instance of LowerTriangular transform.\n        Args:\n            num_matrices: Number of matrices to be stored.\n            squeeze: If num_matrices == 1, drop the redundant axis.\n        \"\"\"\n        self.num_matrices = num_matrices  # We need to store this for reconstruction.\n        self.squeeze = squeeze\n\n    def _validate_vector_length(self, length):\n        \"\"\"\n        Check whether the vector length is consistent with being a triangular\n         matrix and with `self.num_matrices`.\n        Args:\n            length: Length of the free state vector.\n\n        Returns: Length of the vector with the lower triangular elements.\n\n        \"\"\"\n        L = length / self.num_matrices\n        if int(((L * 8) + 1) ** 0.5) ** 2.0 != (L * 8 + 1):\n            raise ValueError(\"The free state must be a triangle number.\")\n        return L\n\n    def forward(self, x):\n        \"\"\"\n        Transforms from the free state to the variable.\n        Args:\n            x: Free state vector. Must have length of `self.num_matrices` *\n                triangular_number.\n\n        Returns:\n            Reconstructed variable.\n        \"\"\"\n        L = self._validate_vector_length(len(x))\n        matsize = int((L * 8 + 1) ** 0.5 * 0.5 - 0.5)\n        xr = np.reshape(x, (self.num_matrices, -1))\n        var = np.zeros((matsize, matsize, self.num_matrices), np_float_type)\n        for i in range(self.num_matrices):\n            indices = np.tril_indices(matsize, 0)\n            var[indices + (np.zeros(len(indices[0])).astype(int) + i,)] = xr[i, :]\n        return var.squeeze() if self.squeeze else var\n\n    def backward(self, y):\n        \"\"\"\n        Transforms from the variable to the free state.\n        Args:\n            y: Variable representation.\n\n        Returns:\n            Free state.\n        \"\"\"\n        N = int((y.size / self.num_matrices) ** 0.5)\n        y = np.reshape(y, (N, N, self.num_matrices))\n        return y[np.tril_indices(len(y), 0)].T.flatten()\n\n    def tf_forward(self, x):\n        fwd = tf.transpose(tfw.vec_to_tri(tf.reshape(x, (self.num_matrices, -1))), [1, 2, 0])\n        return tf.squeeze(fwd) if self.squeeze else fwd\n\n    def tf_log_jacobian(self, x):\n        return tf.zeros((1,), float_type)\n\n    def free_state_size(self, variable_shape):\n        matrix_batch = len(variable_shape) > 2\n        if ((not matrix_batch and self.num_matrices != 1) or\n                (matrix_batch and variable_shape[2] != self.num_matrices)):\n            raise ValueError(\"Number of matrices must be consistent with what was passed to the constructor.\")\n        if variable_shape[0] != variable_shape[1]:\n            raise ValueError(\"Matrices passed must be square.\")\n        N = variable_shape[0]\n        return int(0.5 * N * (N + 1)) * (variable_shape[2] if matrix_batch else 1)\n\n    def __str__(self):\n        return \"LoTri->vec\"\n\n\npositive = Log1pe()\n", "path": "GPflow/transforms.py"}], "after_files": [{"content": "# Copyright 2016 James Hensman, alexggmatthews\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 __future__ import absolute_import\nimport numpy as np\nimport tensorflow as tf\nfrom . import tf_wraps as tfw\nfrom ._settings import settings\n\nfloat_type = settings.dtypes.float_type\nnp_float_type = np.float32 if float_type is tf.float32 else np.float64\n\n\nclass Transform(object):\n    def forward(self, x):\n        \"\"\"\n        Map from the free-space to the variable space, using numpy\n        \"\"\"\n        raise NotImplementedError\n\n    def backward(self, y):\n        \"\"\"\n        Map from the variable-space to the free space, using numpy\n        \"\"\"\n        raise NotImplementedError\n\n    def tf_forward(self, x):\n        \"\"\"\n        Map from the free-space to the variable space, using tensorflow\n        \"\"\"\n        raise NotImplementedError\n\n    def tf_log_jacobian(self, x):\n        \"\"\"\n        Return the log Jacobian of the tf_forward mapping.\n\n        Note that we *could* do this using a tf manipulation of\n        self.tf_forward, but tensorflow may have difficulty: it doesn't have a\n        Jacaobian at time of writing.  We do this in the tests to make sure the\n        implementation is correct.\n        \"\"\"\n        raise NotImplementedError\n\n    def free_state_size(self, variable_shape):\n        return np.prod(variable_shape)\n\n    def __str__(self):\n        \"\"\"\n        A short string describing the nature of the constraint\n        \"\"\"\n        raise NotImplementedError\n\n    def __getstate__(self):\n        return self.__dict__.copy()\n\n    def __setstate__(self, d):\n        self.__dict__ = d\n\n\nclass Identity(Transform):\n    def tf_forward(self, x):\n        return tf.identity(x)\n\n    def forward(self, x):\n        return x\n\n    def backward(self, y):\n        return y\n\n    def tf_log_jacobian(self, x):\n        return tf.zeros((1,), float_type)\n\n    def __str__(self):\n        return '(none)'\n\n\nclass Exp(Transform):\n    def __init__(self, lower=1e-6):\n        self._lower = lower\n\n    def tf_forward(self, x):\n        return tf.exp(x) + self._lower\n\n    def forward(self, x):\n        return np.exp(x) + self._lower\n\n    def backward(self, y):\n        return np.log(y - self._lower)\n\n    def tf_log_jacobian(self, x):\n        return tf.reduce_sum(x)\n\n    def __str__(self):\n        return '+ve'\n\n\nclass Log1pe(Transform):\n    \"\"\"\n    A transform of the form\n\n       y = \\log ( 1 + \\exp(x))\n\n    x is a free variable, y is always positive.\n\n    This function is known as 'softplus' in tensorflow.\n    \"\"\"\n\n    def __init__(self, lower=1e-6):\n        \"\"\"\n        lower is a float that defines the minimum value that this transform can\n        take, default 1e-6. This helps stability during optimization, because\n        aggressive optimizers can take overly-long steps which lead to zero in\n        the transformed variable, causing an error.\n        \"\"\"\n        self._lower = lower\n\n    def forward(self, x):\n        result = np.log(1. + np.exp(x)) + self._lower\n        # do not transform large numbers, they overflow and the mapping is exactly identity.\n        return np.where(x > 35, x + self._lower, result)\n\n    def tf_forward(self, x):\n        return tf.nn.softplus(x) + self._lower\n\n    def tf_log_jacobian(self, x):\n        return -tf.reduce_sum(tf.log(1. + tf.exp(-x)))\n\n    def backward(self, y):\n        result = np.log(np.exp(y - self._lower) - np.ones(1, np_float_type))\n        return np.where(y > 35, y-self._lower, result)\n\n    def __str__(self):\n        return '+ve'\n\n\nclass Logistic(Transform):\n    def __init__(self, a=0., b=1.):\n        Transform.__init__(self)\n        assert b > a\n        self.a, self.b = float(a), float(b)\n\n    def tf_forward(self, x):\n        ex = tf.exp(-x)\n        return self.a + (self.b - self.a) / (1. + ex)\n\n    def forward(self, x):\n        ex = np.exp(-x)\n        return self.a + (self.b - self.a) / (1. + ex)\n\n    def backward(self, y):\n        return -np.log((self.b - self.a) / (y - self.a) - 1.)\n\n    def tf_log_jacobian(self, x):\n        return tf.reduce_sum(x - 2. * tf.log(tf.exp(x) + 1.) + np.log(self.b - self.a))\n\n    def __str__(self):\n        return '[' + str(self.a) + ', ' + str(self.b) + ']'\n\n\nclass DiagMatrix(Transform):\n    \"\"\"\n    A transform to represent diagonal matrices.\n\n    The output of this transform is a N x dim x dim array of diagonal matrices.\n    The contructor argumnet dim specifies the size of the matrixes.\n\n    Additionally, to ensure that the matrices are positive definite, the\n    diagonal elements are pushed through a 'positive' transform, defaulting to\n    log1pe.\n    \"\"\"\n    def __init__(self, dim=1, positive_transform=Log1pe()):\n        self.dim = dim\n        self._lower = 1e-6\n        self._positive_transform = positive_transform\n\n    def forward(self, x):\n        # Create diagonal matrix\n        x = self._positive_transform.forward(x).reshape((-1, self.dim))\n        m = np.zeros((x.shape[0], x.shape[1], x.shape[1]))\n        m[(np.s_[:],) + np.diag_indices(x.shape[1])] = x\n        return m\n\n    def backward(self, y):\n        # Return diagonals of matrices\n        return self._positive_transform.backward(y.reshape(-1, self.dim, self.dim).diagonal(0, 1, 2).flatten())\n\n    def tf_forward(self, x):\n        return tf.matrix_diag(tf.reshape(self._positive_transform.tf_forward(x), (-1, self.dim)))\n\n    def tf_log_jacobian(self, x):\n        return tf.zeros((1,), float_type) + self._positive_transform.tf_log_jacobian(x)\n\n    def __str__(self):\n        return 'DiagMatrix'\n\n    def free_state_size(self, variable_shape):\n        return variable_shape[0] * variable_shape[1]\n\n\nclass LowerTriangular(Transform):\n    \"\"\"\n    A transform of the form\n\n       tri_mat = vec_to_tri(x)\n\n    x is a free variable, y is always a list of lower triangular matrices sized\n    (N x N x D).\n    \"\"\"\n\n    def __init__(self, num_matrices=1, squeeze=False):\n        \"\"\"\n        Create an instance of LowerTriangular transform.\n        Args:\n            num_matrices: Number of matrices to be stored.\n            squeeze: If num_matrices == 1, drop the redundant axis.\n        \"\"\"\n        self.num_matrices = num_matrices  # We need to store this for reconstruction.\n        self.squeeze = squeeze\n\n    def _validate_vector_length(self, length):\n        \"\"\"\n        Check whether the vector length is consistent with being a triangular\n         matrix and with `self.num_matrices`.\n        Args:\n            length: Length of the free state vector.\n\n        Returns: Length of the vector with the lower triangular elements.\n\n        \"\"\"\n        L = length / self.num_matrices\n        if int(((L * 8) + 1) ** 0.5) ** 2.0 != (L * 8 + 1):\n            raise ValueError(\"The free state must be a triangle number.\")\n        return L\n\n    def forward(self, x):\n        \"\"\"\n        Transforms from the free state to the variable.\n        Args:\n            x: Free state vector. Must have length of `self.num_matrices` *\n                triangular_number.\n\n        Returns:\n            Reconstructed variable.\n        \"\"\"\n        L = self._validate_vector_length(len(x))\n        matsize = int((L * 8 + 1) ** 0.5 * 0.5 - 0.5)\n        xr = np.reshape(x, (self.num_matrices, -1))\n        var = np.zeros((matsize, matsize, self.num_matrices), np_float_type)\n        for i in range(self.num_matrices):\n            indices = np.tril_indices(matsize, 0)\n            var[indices + (np.zeros(len(indices[0])).astype(int) + i,)] = xr[i, :]\n        return var.squeeze() if self.squeeze else var\n\n    def backward(self, y):\n        \"\"\"\n        Transforms from the variable to the free state.\n        Args:\n            y: Variable representation.\n\n        Returns:\n            Free state.\n        \"\"\"\n        N = int((y.size / self.num_matrices) ** 0.5)\n        y = np.reshape(y, (N, N, self.num_matrices))\n        return y[np.tril_indices(len(y), 0)].T.flatten()\n\n    def tf_forward(self, x):\n        fwd = tf.transpose(tfw.vec_to_tri(tf.reshape(x, (self.num_matrices, -1))), [1, 2, 0])\n        return tf.squeeze(fwd) if self.squeeze else fwd\n\n    def tf_log_jacobian(self, x):\n        return tf.zeros((1,), float_type)\n\n    def free_state_size(self, variable_shape):\n        matrix_batch = len(variable_shape) > 2\n        if ((not matrix_batch and self.num_matrices != 1) or\n                (matrix_batch and variable_shape[2] != self.num_matrices)):\n            raise ValueError(\"Number of matrices must be consistent with what was passed to the constructor.\")\n        if variable_shape[0] != variable_shape[1]:\n            raise ValueError(\"Matrices passed must be square.\")\n        N = variable_shape[0]\n        return int(0.5 * N * (N + 1)) * (variable_shape[2] if matrix_batch else 1)\n\n    def __str__(self):\n        return \"LoTri->vec\"\n\n\npositive = Log1pe()\n", "path": "GPflow/transforms.py"}]}