We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
BoxUniform should automatically convert to float32
I lost count of how many times I searched for a bug related to this... ;)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sbi/utils/torchutils.py`
Content:
```
1 # This file is part of sbi, a toolkit for simulation-based inference. sbi is licensed
2 # under the Affero General Public License v3, see <https://www.gnu.org/licenses/>.
3 
4 """Various PyTorch utility functions."""
5 
6 import warnings
7 from typing import Union
8 
9 import numpy as np
10 import torch
11 from torch import Tensor, float32
12 from torch.distributions import Independent, Uniform
13 
14 from sbi import utils as utils
15 from sbi.types import Array, OneOrMore, ScalarFloat
16 
17 
18 def process_device(device: str) -> str:
19     """Set and return the default device to cpu or gpu."""
20 
21     if not device == "cpu":
22         if device == "gpu":
23             device = "cuda"
24         try:
25             torch.zeros(1).to(device)
26             warnings.warn(
27                 """GPU was selected as a device for training the neural network. Note
28                    that we expect **no** significant speed ups in training for the
29                    default architectures we provide. Using the GPU will be effective
30                    only for large neural networks with operations that are fast on the
31                    GPU, e.g., for a CNN or RNN `embedding_net`."""
32             )
33         except (RuntimeError, AssertionError):
34             warnings.warn(f"Device {device} not available, falling back to CPU.")
35             device = "cpu"
36 
37     return device
38 
39 
40 def tile(x, n):
41     if not utils.is_positive_int(n):
42         raise TypeError("Argument `n` must be a positive integer.")
43     x_ = x.reshape(-1)
44     x_ = x_.repeat(n)
45     x_ = x_.reshape(n, -1)
46     x_ = x_.transpose(1, 0)
47     x_ = x_.reshape(-1)
48     return x_
49 
50 
51 def sum_except_batch(x, num_batch_dims=1):
52     """Sums all elements of `x` except for the first `num_batch_dims` dimensions."""
53     if not utils.is_nonnegative_int(num_batch_dims):
54         raise TypeError("Number of batch dimensions must be a non-negative integer.")
55     reduce_dims = list(range(num_batch_dims, x.ndimension()))
56     return torch.sum(x, dim=reduce_dims)
57 
58 
59 def split_leading_dim(x, shape):
60     """Reshapes the leading dim of `x` to have the given shape."""
61     new_shape = torch.Size(shape) + x.shape[1:]
62     return torch.reshape(x, new_shape)
63 
64 
65 def merge_leading_dims(x, num_dims):
66     """Reshapes the tensor `x` such that the first `num_dims` dimensions are merged to one."""
67     if not utils.is_positive_int(num_dims):
68         raise TypeError("Number of leading dims must be a positive integer.")
69     if num_dims > x.dim():
70         raise ValueError(
71             "Number of leading dims can't be greater than total number of dims."
72         )
73     new_shape = torch.Size([-1]) + x.shape[num_dims:]
74     return torch.reshape(x, new_shape)
75 
76 
77 def repeat_rows(x, num_reps):
78     """Each row of tensor `x` is repeated `num_reps` times along leading dimension."""
79     if not utils.is_positive_int(num_reps):
80         raise TypeError("Number of repetitions must be a positive integer.")
81     shape = x.shape
82     x = x.unsqueeze(1)
83     x = x.expand(shape[0], num_reps, *shape[1:])
84     return merge_leading_dims(x, num_dims=2)
85 
86 
87 def tensor2numpy(x):
88     return x.detach().cpu().numpy()
89 
90 
91 def logabsdet(x):
92     """Returns the log absolute determinant of square matrix x."""
93     # Note: torch.logdet() only works for positive determinant.
94     _, res = torch.slogdet(x)
95     return res
96 
97 
98 def random_orthogonal(size):
99     """
100     Returns a random orthogonal matrix as a 2-dim tensor of shape [size, size].
101     """
102 
103     # Use the QR decomposition of a random Gaussian matrix.
104     x = torch.randn(size, size)
105     q, _ = torch.qr(x)
106     return q
107 
108 
109 def get_num_parameters(model):
110     """
111     Returns the number of trainable parameters in a model of type nets.Module
112     :param model: nets.Module containing trainable parameters
113     :return: number of trainable parameters in model
114     """
115     num_parameters = 0
116     for parameter in model.parameters():
117         num_parameters += torch.numel(parameter)
118     return num_parameters
119 
120 
121 def create_alternating_binary_mask(features, even=True):
122     """
123     Creates a binary mask of a given dimension which alternates its masking.
124 
125     :param features: Dimension of mask.
126     :param even: If True, even values are assigned 1s, odd 0s. If False, vice versa.
127     :return: Alternating binary mask of type torch.Tensor.
128     """
129     mask = torch.zeros(features).byte()
130     start = 0 if even else 1
131     mask[start::2] += 1
132     return mask
133 
134 
135 def create_mid_split_binary_mask(features):
136     """
137     Creates a binary mask of a given dimension which splits its masking at the midpoint.
138 
139     :param features: Dimension of mask.
140     :return: Binary mask split at midpoint of type torch.Tensor
141     """
142     mask = torch.zeros(features).byte()
143     midpoint = features // 2 if features % 2 == 0 else features // 2 + 1
144     mask[:midpoint] += 1
145     return mask
146 
147 
148 def create_random_binary_mask(features):
149     """
150     Creates a random binary mask of a given dimension with half of its entries
151     randomly set to 1s.
152 
153     :param features: Dimension of mask.
154     :return: Binary mask with half of its entries set to 1s, of type torch.Tensor.
155     """
156     mask = torch.zeros(features).byte()
157     weights = torch.ones(features).float()
158     num_samples = features // 2 if features % 2 == 0 else features // 2 + 1
159     indices = torch.multinomial(
160         input=weights, num_samples=num_samples, replacement=False
161     )
162     mask[indices] += 1
163     return mask
164 
165 
166 def searchsorted(bin_locations, inputs, eps=1e-6):
167     bin_locations[..., -1] += eps
168     return torch.sum(inputs[..., None] >= bin_locations, dim=-1) - 1
169 
170 
171 def cbrt(x):
172     """Cube root. Equivalent to torch.pow(x, 1/3), but numerically stable."""
173     return torch.sign(x) * torch.exp(torch.log(torch.abs(x)) / 3.0)
174 
175 
176 def get_temperature(max_value, bound=1 - 1e-3):
177     """
178     For a dataset with max value 'max_value', returns the temperature such that
179 
180         sigmoid(temperature * max_value) = bound.
181 
182     If temperature is greater than 1, returns 1.
183 
184     :param max_value:
185     :param bound:
186     :return:
187     """
188     max_value = torch.Tensor([max_value])
189     bound = torch.Tensor([bound])
190     temperature = min(-(1 / max_value) * (torch.log1p(-bound) - torch.log(bound)), 1)
191     return temperature
192 
193 
194 def gaussian_kde_log_eval(samples, query):
195     N, D = samples.shape[0], samples.shape[-1]
196     std = N ** (-1 / (D + 4))
197     precision = (1 / (std ** 2)) * torch.eye(D)
198     a = query - samples
199     b = a @ precision
200     c = -0.5 * torch.sum(a * b, dim=-1)
201     d = -np.log(N) - (D / 2) * np.log(2 * np.pi) - D * np.log(std)
202     c += d
203     return torch.logsumexp(c, dim=-1)
204 
205 
206 class BoxUniform(Independent):
207     def __init__(
208         self, low: ScalarFloat, high: ScalarFloat, reinterpreted_batch_ndims: int = 1,
209     ):
210         """Multidimensional uniform distribution defined on a box.
211 
212         A `Uniform` distribution initialized with e.g. a parameter vector low or high of
213          length 3 will result in a /batch/ dimension of length 3. A log_prob evaluation
214          will then output three numbers, one for each of the independent Uniforms in
215          the batch. Instead, a `BoxUniform` initialized in the same way has three
216          /event/ dimensions, and returns a scalar log_prob corresponding to whether
217          the evaluated point is in the box defined by low and high or outside.
218 
219         Refer to torch.distributions.Uniform and torch.distributions.Independent for
220          further documentation.
221 
222         Args:
223             low: lower range (inclusive).
224             high: upper range (exclusive).
225             reinterpreted_batch_ndims (int): the number of batch dims to
226                                              reinterpret as event dims.
227         """
228 
229         super().__init__(Uniform(low=low, high=high), reinterpreted_batch_ndims)
230 
231 
232 def ensure_theta_batched(theta: Tensor) -> Tensor:
233     r"""
234     Return parameter set theta that has a batch dimension, i.e. has shape
235      (1, shape_of_single_theta)
236 
237      Args:
238          theta: parameters $\theta$, of shape (n) or (1,n)
239      Returns:
240          Batched parameter set $\theta$
241     """
242 
243     # => ensure theta has shape (1, dim_parameter)
244     if theta.ndim == 1:
245         theta = theta.unsqueeze(0)
246 
247     return theta
248 
249 
250 def ensure_x_batched(x: Tensor) -> Tensor:
251     """
252     Return simulation output x that has a batch dimension, i.e. has shape
253     (1, shape_of_single_x).
254 
255     Args:
256          x: simulation output of shape (n) or (1,n).
257      Returns:
258          Batched simulation output x.
259     """
260 
261     # ensure x has shape (1, shape_of_single_x). If shape[0] > 1, we assume that
262     # the batch-dimension is missing, even though ndim might be >1 (e.g. for images)
263     if x.shape[0] > 1 or x.ndim == 1:
264         x = x.unsqueeze(0)
265 
266     return x
267 
268 
269 def atleast_2d_many(*arys: Array) -> OneOrMore[Tensor]:
270     """Return tensors with at least dimension 2.
271 
272     Tensors or arrays of dimension 0 or 1 will get additional dimension(s) prepended.
273 
274     Returns:
275         Tensor or list of tensors all with dimension >= 2.
276     """
277     if len(arys) == 1:
278         arr = arys[0]
279         if isinstance(arr, np.ndarray):
280             arr = torch.from_numpy(arr)
281         return atleast_2d(arr)
282     else:
283         return [atleast_2d_many(arr) for arr in arys]
284 
285 
286 def atleast_2d(t: Tensor) -> Tensor:
287     return t if t.ndim >= 2 else t.reshape(1, -1)
288 
289 
290 def maybe_add_batch_dim_to_size(s: torch.Size) -> torch.Size:
291     """
292     Take a torch.Size and add a batch dimension to it if dimensionality of size is 1.
293 
294     (N) -> (1,N)
295     (1,N) -> (1,N)
296     (N,M) -> (N,M)
297     (1,N,M) -> (1,N,M)
298 
299     Args:
300         s: Input size, possibly without batch dimension.
301 
302     Returns: Batch size.
303 
304     """
305     return s if len(s) >= 2 else torch.Size([1]) + s
306 
307 
308 def atleast_2d_float32_tensor(arr: Union[Tensor, np.ndarray]) -> Tensor:
309     return atleast_2d(torch.as_tensor(arr, dtype=float32))
310 
311 
312 def batched_first_of_batch(t: Tensor) -> Tensor:
313     """
314     Takes in a tensor of shape (N, M) and outputs tensor of shape (1,M).
315     """
316     return t[:1]
317
```
--- 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/sbi/utils/torchutils.py b/sbi/utils/torchutils.py
--- a/sbi/utils/torchutils.py
+++ b/sbi/utils/torchutils.py
@@ -226,7 +226,13 @@
                                              reinterpret as event dims.
         """
 
-        super().__init__(Uniform(low=low, high=high), reinterpreted_batch_ndims)
+        super().__init__(
+            Uniform(
+                low=torch.as_tensor(low, dtype=torch.float32),
+                high=torch.as_tensor(high, dtype=torch.float32),
+            ),
+            reinterpreted_batch_ndims,
+        )
 
 
 def ensure_theta_batched(theta: Tensor) -> Tensor:

{"golden_diff": "diff --git a/sbi/utils/torchutils.py b/sbi/utils/torchutils.py\n--- a/sbi/utils/torchutils.py\n+++ b/sbi/utils/torchutils.py\n@@ -226,7 +226,13 @@\n                                              reinterpret as event dims.\n         \"\"\"\n \n-        super().__init__(Uniform(low=low, high=high), reinterpreted_batch_ndims)\n+        super().__init__(\n+            Uniform(\n+                low=torch.as_tensor(low, dtype=torch.float32),\n+                high=torch.as_tensor(high, dtype=torch.float32),\n+            ),\n+            reinterpreted_batch_ndims,\n+        )\n \n \n def ensure_theta_batched(theta: Tensor) -> Tensor:\n", "issue": "BoxUniform should automatically convert to float32\nI lost count of how many times I searched for a bug related to this... ;)\n", "before_files": [{"content": "# This file is part of sbi, a toolkit for simulation-based inference. sbi is licensed\n# under the Affero General Public License v3, see <https://www.gnu.org/licenses/>.\n\n\"\"\"Various PyTorch utility functions.\"\"\"\n\nimport warnings\nfrom typing import Union\n\nimport numpy as np\nimport torch\nfrom torch import Tensor, float32\nfrom torch.distributions import Independent, Uniform\n\nfrom sbi import utils as utils\nfrom sbi.types import Array, OneOrMore, ScalarFloat\n\n\ndef process_device(device: str) -> str:\n    \"\"\"Set and return the default device to cpu or gpu.\"\"\"\n\n    if not device == \"cpu\":\n        if device == \"gpu\":\n            device = \"cuda\"\n        try:\n            torch.zeros(1).to(device)\n            warnings.warn(\n                \"\"\"GPU was selected as a device for training the neural network. Note\n                   that we expect **no** significant speed ups in training for the\n                   default architectures we provide. Using the GPU will be effective\n                   only for large neural networks with operations that are fast on the\n                   GPU, e.g., for a CNN or RNN `embedding_net`.\"\"\"\n            )\n        except (RuntimeError, AssertionError):\n            warnings.warn(f\"Device {device} not available, falling back to CPU.\")\n            device = \"cpu\"\n\n    return device\n\n\ndef tile(x, n):\n    if not utils.is_positive_int(n):\n        raise TypeError(\"Argument `n` must be a positive integer.\")\n    x_ = x.reshape(-1)\n    x_ = x_.repeat(n)\n    x_ = x_.reshape(n, -1)\n    x_ = x_.transpose(1, 0)\n    x_ = x_.reshape(-1)\n    return x_\n\n\ndef sum_except_batch(x, num_batch_dims=1):\n    \"\"\"Sums all elements of `x` except for the first `num_batch_dims` dimensions.\"\"\"\n    if not utils.is_nonnegative_int(num_batch_dims):\n        raise TypeError(\"Number of batch dimensions must be a non-negative integer.\")\n    reduce_dims = list(range(num_batch_dims, x.ndimension()))\n    return torch.sum(x, dim=reduce_dims)\n\n\ndef split_leading_dim(x, shape):\n    \"\"\"Reshapes the leading dim of `x` to have the given shape.\"\"\"\n    new_shape = torch.Size(shape) + x.shape[1:]\n    return torch.reshape(x, new_shape)\n\n\ndef merge_leading_dims(x, num_dims):\n    \"\"\"Reshapes the tensor `x` such that the first `num_dims` dimensions are merged to one.\"\"\"\n    if not utils.is_positive_int(num_dims):\n        raise TypeError(\"Number of leading dims must be a positive integer.\")\n    if num_dims > x.dim():\n        raise ValueError(\n            \"Number of leading dims can't be greater than total number of dims.\"\n        )\n    new_shape = torch.Size([-1]) + x.shape[num_dims:]\n    return torch.reshape(x, new_shape)\n\n\ndef repeat_rows(x, num_reps):\n    \"\"\"Each row of tensor `x` is repeated `num_reps` times along leading dimension.\"\"\"\n    if not utils.is_positive_int(num_reps):\n        raise TypeError(\"Number of repetitions must be a positive integer.\")\n    shape = x.shape\n    x = x.unsqueeze(1)\n    x = x.expand(shape[0], num_reps, *shape[1:])\n    return merge_leading_dims(x, num_dims=2)\n\n\ndef tensor2numpy(x):\n    return x.detach().cpu().numpy()\n\n\ndef logabsdet(x):\n    \"\"\"Returns the log absolute determinant of square matrix x.\"\"\"\n    # Note: torch.logdet() only works for positive determinant.\n    _, res = torch.slogdet(x)\n    return res\n\n\ndef random_orthogonal(size):\n    \"\"\"\n    Returns a random orthogonal matrix as a 2-dim tensor of shape [size, size].\n    \"\"\"\n\n    # Use the QR decomposition of a random Gaussian matrix.\n    x = torch.randn(size, size)\n    q, _ = torch.qr(x)\n    return q\n\n\ndef get_num_parameters(model):\n    \"\"\"\n    Returns the number of trainable parameters in a model of type nets.Module\n    :param model: nets.Module containing trainable parameters\n    :return: number of trainable parameters in model\n    \"\"\"\n    num_parameters = 0\n    for parameter in model.parameters():\n        num_parameters += torch.numel(parameter)\n    return num_parameters\n\n\ndef create_alternating_binary_mask(features, even=True):\n    \"\"\"\n    Creates a binary mask of a given dimension which alternates its masking.\n\n    :param features: Dimension of mask.\n    :param even: If True, even values are assigned 1s, odd 0s. If False, vice versa.\n    :return: Alternating binary mask of type torch.Tensor.\n    \"\"\"\n    mask = torch.zeros(features).byte()\n    start = 0 if even else 1\n    mask[start::2] += 1\n    return mask\n\n\ndef create_mid_split_binary_mask(features):\n    \"\"\"\n    Creates a binary mask of a given dimension which splits its masking at the midpoint.\n\n    :param features: Dimension of mask.\n    :return: Binary mask split at midpoint of type torch.Tensor\n    \"\"\"\n    mask = torch.zeros(features).byte()\n    midpoint = features // 2 if features % 2 == 0 else features // 2 + 1\n    mask[:midpoint] += 1\n    return mask\n\n\ndef create_random_binary_mask(features):\n    \"\"\"\n    Creates a random binary mask of a given dimension with half of its entries\n    randomly set to 1s.\n\n    :param features: Dimension of mask.\n    :return: Binary mask with half of its entries set to 1s, of type torch.Tensor.\n    \"\"\"\n    mask = torch.zeros(features).byte()\n    weights = torch.ones(features).float()\n    num_samples = features // 2 if features % 2 == 0 else features // 2 + 1\n    indices = torch.multinomial(\n        input=weights, num_samples=num_samples, replacement=False\n    )\n    mask[indices] += 1\n    return mask\n\n\ndef searchsorted(bin_locations, inputs, eps=1e-6):\n    bin_locations[..., -1] += eps\n    return torch.sum(inputs[..., None] >= bin_locations, dim=-1) - 1\n\n\ndef cbrt(x):\n    \"\"\"Cube root. Equivalent to torch.pow(x, 1/3), but numerically stable.\"\"\"\n    return torch.sign(x) * torch.exp(torch.log(torch.abs(x)) / 3.0)\n\n\ndef get_temperature(max_value, bound=1 - 1e-3):\n    \"\"\"\n    For a dataset with max value 'max_value', returns the temperature such that\n\n        sigmoid(temperature * max_value) = bound.\n\n    If temperature is greater than 1, returns 1.\n\n    :param max_value:\n    :param bound:\n    :return:\n    \"\"\"\n    max_value = torch.Tensor([max_value])\n    bound = torch.Tensor([bound])\n    temperature = min(-(1 / max_value) * (torch.log1p(-bound) - torch.log(bound)), 1)\n    return temperature\n\n\ndef gaussian_kde_log_eval(samples, query):\n    N, D = samples.shape[0], samples.shape[-1]\n    std = N ** (-1 / (D + 4))\n    precision = (1 / (std ** 2)) * torch.eye(D)\n    a = query - samples\n    b = a @ precision\n    c = -0.5 * torch.sum(a * b, dim=-1)\n    d = -np.log(N) - (D / 2) * np.log(2 * np.pi) - D * np.log(std)\n    c += d\n    return torch.logsumexp(c, dim=-1)\n\n\nclass BoxUniform(Independent):\n    def __init__(\n        self, low: ScalarFloat, high: ScalarFloat, reinterpreted_batch_ndims: int = 1,\n    ):\n        \"\"\"Multidimensional uniform distribution defined on a box.\n\n        A `Uniform` distribution initialized with e.g. a parameter vector low or high of\n         length 3 will result in a /batch/ dimension of length 3. A log_prob evaluation\n         will then output three numbers, one for each of the independent Uniforms in\n         the batch. Instead, a `BoxUniform` initialized in the same way has three\n         /event/ dimensions, and returns a scalar log_prob corresponding to whether\n         the evaluated point is in the box defined by low and high or outside.\n\n        Refer to torch.distributions.Uniform and torch.distributions.Independent for\n         further documentation.\n\n        Args:\n            low: lower range (inclusive).\n            high: upper range (exclusive).\n            reinterpreted_batch_ndims (int): the number of batch dims to\n                                             reinterpret as event dims.\n        \"\"\"\n\n        super().__init__(Uniform(low=low, high=high), reinterpreted_batch_ndims)\n\n\ndef ensure_theta_batched(theta: Tensor) -> Tensor:\n    r\"\"\"\n    Return parameter set theta that has a batch dimension, i.e. has shape\n     (1, shape_of_single_theta)\n\n     Args:\n         theta: parameters $\\theta$, of shape (n) or (1,n)\n     Returns:\n         Batched parameter set $\\theta$\n    \"\"\"\n\n    # => ensure theta has shape (1, dim_parameter)\n    if theta.ndim == 1:\n        theta = theta.unsqueeze(0)\n\n    return theta\n\n\ndef ensure_x_batched(x: Tensor) -> Tensor:\n    \"\"\"\n    Return simulation output x that has a batch dimension, i.e. has shape\n    (1, shape_of_single_x).\n\n    Args:\n         x: simulation output of shape (n) or (1,n).\n     Returns:\n         Batched simulation output x.\n    \"\"\"\n\n    # ensure x has shape (1, shape_of_single_x). If shape[0] > 1, we assume that\n    # the batch-dimension is missing, even though ndim might be >1 (e.g. for images)\n    if x.shape[0] > 1 or x.ndim == 1:\n        x = x.unsqueeze(0)\n\n    return x\n\n\ndef atleast_2d_many(*arys: Array) -> OneOrMore[Tensor]:\n    \"\"\"Return tensors with at least dimension 2.\n\n    Tensors or arrays of dimension 0 or 1 will get additional dimension(s) prepended.\n\n    Returns:\n        Tensor or list of tensors all with dimension >= 2.\n    \"\"\"\n    if len(arys) == 1:\n        arr = arys[0]\n        if isinstance(arr, np.ndarray):\n            arr = torch.from_numpy(arr)\n        return atleast_2d(arr)\n    else:\n        return [atleast_2d_many(arr) for arr in arys]\n\n\ndef atleast_2d(t: Tensor) -> Tensor:\n    return t if t.ndim >= 2 else t.reshape(1, -1)\n\n\ndef maybe_add_batch_dim_to_size(s: torch.Size) -> torch.Size:\n    \"\"\"\n    Take a torch.Size and add a batch dimension to it if dimensionality of size is 1.\n\n    (N) -> (1,N)\n    (1,N) -> (1,N)\n    (N,M) -> (N,M)\n    (1,N,M) -> (1,N,M)\n\n    Args:\n        s: Input size, possibly without batch dimension.\n\n    Returns: Batch size.\n\n    \"\"\"\n    return s if len(s) >= 2 else torch.Size([1]) + s\n\n\ndef atleast_2d_float32_tensor(arr: Union[Tensor, np.ndarray]) -> Tensor:\n    return atleast_2d(torch.as_tensor(arr, dtype=float32))\n\n\ndef batched_first_of_batch(t: Tensor) -> Tensor:\n    \"\"\"\n    Takes in a tensor of shape (N, M) and outputs tensor of shape (1,M).\n    \"\"\"\n    return t[:1]\n", "path": "sbi/utils/torchutils.py"}], "after_files": [{"content": "# This file is part of sbi, a toolkit for simulation-based inference. sbi is licensed\n# under the Affero General Public License v3, see <https://www.gnu.org/licenses/>.\n\n\"\"\"Various PyTorch utility functions.\"\"\"\n\nimport warnings\nfrom typing import Union\n\nimport numpy as np\nimport torch\nfrom torch import Tensor, float32\nfrom torch.distributions import Independent, Uniform\n\nfrom sbi import utils as utils\nfrom sbi.types import Array, OneOrMore, ScalarFloat\n\n\ndef process_device(device: str) -> str:\n    \"\"\"Set and return the default device to cpu or gpu.\"\"\"\n\n    if not device == \"cpu\":\n        if device == \"gpu\":\n            device = \"cuda\"\n        try:\n            torch.zeros(1).to(device)\n            warnings.warn(\n                \"\"\"GPU was selected as a device for training the neural network. Note\n                   that we expect **no** significant speed ups in training for the\n                   default architectures we provide. Using the GPU will be effective\n                   only for large neural networks with operations that are fast on the\n                   GPU, e.g., for a CNN or RNN `embedding_net`.\"\"\"\n            )\n        except (RuntimeError, AssertionError):\n            warnings.warn(f\"Device {device} not available, falling back to CPU.\")\n            device = \"cpu\"\n\n    return device\n\n\ndef tile(x, n):\n    if not utils.is_positive_int(n):\n        raise TypeError(\"Argument `n` must be a positive integer.\")\n    x_ = x.reshape(-1)\n    x_ = x_.repeat(n)\n    x_ = x_.reshape(n, -1)\n    x_ = x_.transpose(1, 0)\n    x_ = x_.reshape(-1)\n    return x_\n\n\ndef sum_except_batch(x, num_batch_dims=1):\n    \"\"\"Sums all elements of `x` except for the first `num_batch_dims` dimensions.\"\"\"\n    if not utils.is_nonnegative_int(num_batch_dims):\n        raise TypeError(\"Number of batch dimensions must be a non-negative integer.\")\n    reduce_dims = list(range(num_batch_dims, x.ndimension()))\n    return torch.sum(x, dim=reduce_dims)\n\n\ndef split_leading_dim(x, shape):\n    \"\"\"Reshapes the leading dim of `x` to have the given shape.\"\"\"\n    new_shape = torch.Size(shape) + x.shape[1:]\n    return torch.reshape(x, new_shape)\n\n\ndef merge_leading_dims(x, num_dims):\n    \"\"\"Reshapes the tensor `x` such that the first `num_dims` dimensions are merged to one.\"\"\"\n    if not utils.is_positive_int(num_dims):\n        raise TypeError(\"Number of leading dims must be a positive integer.\")\n    if num_dims > x.dim():\n        raise ValueError(\n            \"Number of leading dims can't be greater than total number of dims.\"\n        )\n    new_shape = torch.Size([-1]) + x.shape[num_dims:]\n    return torch.reshape(x, new_shape)\n\n\ndef repeat_rows(x, num_reps):\n    \"\"\"Each row of tensor `x` is repeated `num_reps` times along leading dimension.\"\"\"\n    if not utils.is_positive_int(num_reps):\n        raise TypeError(\"Number of repetitions must be a positive integer.\")\n    shape = x.shape\n    x = x.unsqueeze(1)\n    x = x.expand(shape[0], num_reps, *shape[1:])\n    return merge_leading_dims(x, num_dims=2)\n\n\ndef tensor2numpy(x):\n    return x.detach().cpu().numpy()\n\n\ndef logabsdet(x):\n    \"\"\"Returns the log absolute determinant of square matrix x.\"\"\"\n    # Note: torch.logdet() only works for positive determinant.\n    _, res = torch.slogdet(x)\n    return res\n\n\ndef random_orthogonal(size):\n    \"\"\"\n    Returns a random orthogonal matrix as a 2-dim tensor of shape [size, size].\n    \"\"\"\n\n    # Use the QR decomposition of a random Gaussian matrix.\n    x = torch.randn(size, size)\n    q, _ = torch.qr(x)\n    return q\n\n\ndef get_num_parameters(model):\n    \"\"\"\n    Returns the number of trainable parameters in a model of type nets.Module\n    :param model: nets.Module containing trainable parameters\n    :return: number of trainable parameters in model\n    \"\"\"\n    num_parameters = 0\n    for parameter in model.parameters():\n        num_parameters += torch.numel(parameter)\n    return num_parameters\n\n\ndef create_alternating_binary_mask(features, even=True):\n    \"\"\"\n    Creates a binary mask of a given dimension which alternates its masking.\n\n    :param features: Dimension of mask.\n    :param even: If True, even values are assigned 1s, odd 0s. If False, vice versa.\n    :return: Alternating binary mask of type torch.Tensor.\n    \"\"\"\n    mask = torch.zeros(features).byte()\n    start = 0 if even else 1\n    mask[start::2] += 1\n    return mask\n\n\ndef create_mid_split_binary_mask(features):\n    \"\"\"\n    Creates a binary mask of a given dimension which splits its masking at the midpoint.\n\n    :param features: Dimension of mask.\n    :return: Binary mask split at midpoint of type torch.Tensor\n    \"\"\"\n    mask = torch.zeros(features).byte()\n    midpoint = features // 2 if features % 2 == 0 else features // 2 + 1\n    mask[:midpoint] += 1\n    return mask\n\n\ndef create_random_binary_mask(features):\n    \"\"\"\n    Creates a random binary mask of a given dimension with half of its entries\n    randomly set to 1s.\n\n    :param features: Dimension of mask.\n    :return: Binary mask with half of its entries set to 1s, of type torch.Tensor.\n    \"\"\"\n    mask = torch.zeros(features).byte()\n    weights = torch.ones(features).float()\n    num_samples = features // 2 if features % 2 == 0 else features // 2 + 1\n    indices = torch.multinomial(\n        input=weights, num_samples=num_samples, replacement=False\n    )\n    mask[indices] += 1\n    return mask\n\n\ndef searchsorted(bin_locations, inputs, eps=1e-6):\n    bin_locations[..., -1] += eps\n    return torch.sum(inputs[..., None] >= bin_locations, dim=-1) - 1\n\n\ndef cbrt(x):\n    \"\"\"Cube root. Equivalent to torch.pow(x, 1/3), but numerically stable.\"\"\"\n    return torch.sign(x) * torch.exp(torch.log(torch.abs(x)) / 3.0)\n\n\ndef get_temperature(max_value, bound=1 - 1e-3):\n    \"\"\"\n    For a dataset with max value 'max_value', returns the temperature such that\n\n        sigmoid(temperature * max_value) = bound.\n\n    If temperature is greater than 1, returns 1.\n\n    :param max_value:\n    :param bound:\n    :return:\n    \"\"\"\n    max_value = torch.Tensor([max_value])\n    bound = torch.Tensor([bound])\n    temperature = min(-(1 / max_value) * (torch.log1p(-bound) - torch.log(bound)), 1)\n    return temperature\n\n\ndef gaussian_kde_log_eval(samples, query):\n    N, D = samples.shape[0], samples.shape[-1]\n    std = N ** (-1 / (D + 4))\n    precision = (1 / (std ** 2)) * torch.eye(D)\n    a = query - samples\n    b = a @ precision\n    c = -0.5 * torch.sum(a * b, dim=-1)\n    d = -np.log(N) - (D / 2) * np.log(2 * np.pi) - D * np.log(std)\n    c += d\n    return torch.logsumexp(c, dim=-1)\n\n\nclass BoxUniform(Independent):\n    def __init__(\n        self, low: ScalarFloat, high: ScalarFloat, reinterpreted_batch_ndims: int = 1,\n    ):\n        \"\"\"Multidimensional uniform distribution defined on a box.\n\n        A `Uniform` distribution initialized with e.g. a parameter vector low or high of\n         length 3 will result in a /batch/ dimension of length 3. A log_prob evaluation\n         will then output three numbers, one for each of the independent Uniforms in\n         the batch. Instead, a `BoxUniform` initialized in the same way has three\n         /event/ dimensions, and returns a scalar log_prob corresponding to whether\n         the evaluated point is in the box defined by low and high or outside.\n\n        Refer to torch.distributions.Uniform and torch.distributions.Independent for\n         further documentation.\n\n        Args:\n            low: lower range (inclusive).\n            high: upper range (exclusive).\n            reinterpreted_batch_ndims (int): the number of batch dims to\n                                             reinterpret as event dims.\n        \"\"\"\n\n        super().__init__(\n            Uniform(\n                low=torch.as_tensor(low, dtype=torch.float32),\n                high=torch.as_tensor(high, dtype=torch.float32),\n            ),\n            reinterpreted_batch_ndims,\n        )\n\n\ndef ensure_theta_batched(theta: Tensor) -> Tensor:\n    r\"\"\"\n    Return parameter set theta that has a batch dimension, i.e. has shape\n     (1, shape_of_single_theta)\n\n     Args:\n         theta: parameters $\\theta$, of shape (n) or (1,n)\n     Returns:\n         Batched parameter set $\\theta$\n    \"\"\"\n\n    # => ensure theta has shape (1, dim_parameter)\n    if theta.ndim == 1:\n        theta = theta.unsqueeze(0)\n\n    return theta\n\n\ndef ensure_x_batched(x: Tensor) -> Tensor:\n    \"\"\"\n    Return simulation output x that has a batch dimension, i.e. has shape\n    (1, shape_of_single_x).\n\n    Args:\n         x: simulation output of shape (n) or (1,n).\n     Returns:\n         Batched simulation output x.\n    \"\"\"\n\n    # ensure x has shape (1, shape_of_single_x). If shape[0] > 1, we assume that\n    # the batch-dimension is missing, even though ndim might be >1 (e.g. for images)\n    if x.shape[0] > 1 or x.ndim == 1:\n        x = x.unsqueeze(0)\n\n    return x\n\n\ndef atleast_2d_many(*arys: Array) -> OneOrMore[Tensor]:\n    \"\"\"Return tensors with at least dimension 2.\n\n    Tensors or arrays of dimension 0 or 1 will get additional dimension(s) prepended.\n\n    Returns:\n        Tensor or list of tensors all with dimension >= 2.\n    \"\"\"\n    if len(arys) == 1:\n        arr = arys[0]\n        if isinstance(arr, np.ndarray):\n            arr = torch.from_numpy(arr)\n        return atleast_2d(arr)\n    else:\n        return [atleast_2d_many(arr) for arr in arys]\n\n\ndef atleast_2d(t: Tensor) -> Tensor:\n    return t if t.ndim >= 2 else t.reshape(1, -1)\n\n\ndef maybe_add_batch_dim_to_size(s: torch.Size) -> torch.Size:\n    \"\"\"\n    Take a torch.Size and add a batch dimension to it if dimensionality of size is 1.\n\n    (N) -> (1,N)\n    (1,N) -> (1,N)\n    (N,M) -> (N,M)\n    (1,N,M) -> (1,N,M)\n\n    Args:\n        s: Input size, possibly without batch dimension.\n\n    Returns: Batch size.\n\n    \"\"\"\n    return s if len(s) >= 2 else torch.Size([1]) + s\n\n\ndef atleast_2d_float32_tensor(arr: Union[Tensor, np.ndarray]) -> Tensor:\n    return atleast_2d(torch.as_tensor(arr, dtype=float32))\n\n\ndef batched_first_of_batch(t: Tensor) -> Tensor:\n    \"\"\"\n    Takes in a tensor of shape (N, M) and outputs tensor of shape (1,M).\n    \"\"\"\n    return t[:1]\n", "path": "sbi/utils/torchutils.py"}]}