We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[Proposal] Simplify the Box string representation
### Proposal 

Stop the `Box` string representation from printing out all the low/high values if they are all identical

### Motivation

In any reasonably large environment, `print(env.observation_space)` will spam the output with dozens of zero's or infs or whatever else. This information may be relevant if some of these values are different, but often is not necessary, and is just noise. And good luck printing a Dictionary observation space.

I think it'd be enough to change the __repr__ method on Box so that if `len(set(self.low)) == 1`, we just print the unique value, and the same thing for `self.high`.

### Pitch

Make Boxes printable again

### Alternatives

Grin and bear it

### Additional context

![image](https://user-images.githubusercontent.com/19414946/143067427-b2b999ba-e430-458a-81c3-f633db2a7b8f.png)
Help

This is partially going back on #2182 and #2183 , but I wasn't around to yell alarm at the full consequences of that PR. But since it will only simplify the representation when all limits are equal, it doesn't actually cause that same problem.

### Checklist

- [x] I have checked that there is no similar [issue](https://github.com/openai/gym/issues) in the repo (**required**)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gym/spaces/box.py`
Content:
```
1 import numpy as np
2 
3 from .space import Space
4 from gym import logger
5 
6 
7 class Box(Space):
8     """
9     A (possibly unbounded) box in R^n. Specifically, a Box represents the
10     Cartesian product of n closed intervals. Each interval has the form of one
11     of [a, b], (-oo, b], [a, oo), or (-oo, oo).
12 
13     There are two common use cases:
14 
15     * Identical bound for each dimension::
16         >>> Box(low=-1.0, high=2.0, shape=(3, 4), dtype=np.float32)
17         Box(3, 4)
18 
19     * Independent bound for each dimension::
20         >>> Box(low=np.array([-1.0, -2.0]), high=np.array([2.0, 4.0]), dtype=np.float32)
21         Box(2,)
22 
23     """
24 
25     def __init__(self, low, high, shape=None, dtype=np.float32, seed=None):
26         assert dtype is not None, "dtype must be explicitly provided. "
27         self.dtype = np.dtype(dtype)
28 
29         # determine shape if it isn't provided directly
30         if shape is not None:
31             shape = tuple(shape)
32             assert (
33                 np.isscalar(low) or low.shape == shape
34             ), "low.shape doesn't match provided shape"
35             assert (
36                 np.isscalar(high) or high.shape == shape
37             ), "high.shape doesn't match provided shape"
38         elif not np.isscalar(low):
39             shape = low.shape
40             assert (
41                 np.isscalar(high) or high.shape == shape
42             ), "high.shape doesn't match low.shape"
43         elif not np.isscalar(high):
44             shape = high.shape
45             assert (
46                 np.isscalar(low) or low.shape == shape
47             ), "low.shape doesn't match high.shape"
48         else:
49             raise ValueError(
50                 "shape must be provided or inferred from the shapes of low or high"
51             )
52 
53         # handle infinite bounds and broadcast at the same time if needed
54         if np.isscalar(low):
55             low = get_inf(dtype, "-") if np.isinf(low) else low
56             low = np.full(shape, low, dtype=dtype)
57         else:
58             if np.any(np.isinf(low)):
59                 # create new array with dtype, but maintain old one to preserve np.inf
60                 temp_low = low.astype(dtype)
61                 temp_low[np.isinf(low)] = get_inf(dtype, "-")
62                 low = temp_low
63 
64         if np.isscalar(high):
65             high = get_inf(dtype, "+") if np.isinf(high) else high
66             high = np.full(shape, high, dtype=dtype)
67         else:
68             if np.any(np.isinf(high)):
69                 # create new array with dtype, but maintain old one to preserve np.inf
70                 temp_high = high.astype(dtype)
71                 temp_high[np.isinf(high)] = get_inf(dtype, "+")
72                 high = temp_high
73 
74         self._shape = shape
75         self.low = low
76         self.high = high
77 
78         low_precision = get_precision(self.low.dtype)
79         high_precision = get_precision(self.high.dtype)
80         dtype_precision = get_precision(self.dtype)
81         if min(low_precision, high_precision) > dtype_precision:
82             logger.warn(f"Box bound precision lowered by casting to {self.dtype}")
83         self.low = self.low.astype(self.dtype)
84         self.high = self.high.astype(self.dtype)
85 
86         # Boolean arrays which indicate the interval type for each coordinate
87         self.bounded_below = -np.inf < self.low
88         self.bounded_above = np.inf > self.high
89 
90         super().__init__(self.shape, self.dtype, seed)
91 
92     def is_bounded(self, manner="both"):
93         below = np.all(self.bounded_below)
94         above = np.all(self.bounded_above)
95         if manner == "both":
96             return below and above
97         elif manner == "below":
98             return below
99         elif manner == "above":
100             return above
101         else:
102             raise ValueError("manner is not in {'below', 'above', 'both'}")
103 
104     def sample(self):
105         """
106         Generates a single random sample inside of the Box.
107 
108         In creating a sample of the box, each coordinate is sampled according to
109         the form of the interval:
110 
111         * [a, b] : uniform distribution
112         * [a, oo) : shifted exponential distribution
113         * (-oo, b] : shifted negative exponential distribution
114         * (-oo, oo) : normal distribution
115         """
116         high = self.high if self.dtype.kind == "f" else self.high.astype("int64") + 1
117         sample = np.empty(self.shape)
118 
119         # Masking arrays which classify the coordinates according to interval
120         # type
121         unbounded = ~self.bounded_below & ~self.bounded_above
122         upp_bounded = ~self.bounded_below & self.bounded_above
123         low_bounded = self.bounded_below & ~self.bounded_above
124         bounded = self.bounded_below & self.bounded_above
125 
126         # Vectorized sampling by interval type
127         sample[unbounded] = self.np_random.normal(size=unbounded[unbounded].shape)
128 
129         sample[low_bounded] = (
130             self.np_random.exponential(size=low_bounded[low_bounded].shape)
131             + self.low[low_bounded]
132         )
133 
134         sample[upp_bounded] = (
135             -self.np_random.exponential(size=upp_bounded[upp_bounded].shape)
136             + self.high[upp_bounded]
137         )
138 
139         sample[bounded] = self.np_random.uniform(
140             low=self.low[bounded], high=high[bounded], size=bounded[bounded].shape
141         )
142         if self.dtype.kind == "i":
143             sample = np.floor(sample)
144 
145         return sample.astype(self.dtype)
146 
147     def contains(self, x):
148         if not isinstance(x, np.ndarray):
149             logger.warn("Casting input x to numpy array.")
150             x = np.asarray(x, dtype=self.dtype)
151 
152         return (
153             np.can_cast(x.dtype, self.dtype)
154             and x.shape == self.shape
155             and np.all(x >= self.low)
156             and np.all(x <= self.high)
157         )
158 
159     def to_jsonable(self, sample_n):
160         return np.array(sample_n).tolist()
161 
162     def from_jsonable(self, sample_n):
163         return [np.asarray(sample) for sample in sample_n]
164 
165     def __repr__(self):
166         return f"Box({self.low}, {self.high}, {self.shape}, {self.dtype})"
167 
168     def __eq__(self, other):
169         return (
170             isinstance(other, Box)
171             and (self.shape == other.shape)
172             and np.allclose(self.low, other.low)
173             and np.allclose(self.high, other.high)
174         )
175 
176 
177 def get_inf(dtype, sign):
178     """Returns an infinite that doesn't break things.
179     `dtype` must be an `np.dtype`
180     `bound` must be either `min` or `max`
181     """
182     if np.dtype(dtype).kind == "f":
183         if sign == "+":
184             return np.inf
185         elif sign == "-":
186             return -np.inf
187         else:
188             raise TypeError(f"Unknown sign {sign}, use either '+' or '-'")
189     elif np.dtype(dtype).kind == "i":
190         if sign == "+":
191             return np.iinfo(dtype).max - 2
192         elif sign == "-":
193             return np.iinfo(dtype).min + 2
194         else:
195             raise TypeError(f"Unknown sign {sign}, use either '+' or '-'")
196     else:
197         raise ValueError(f"Unknown dtype {dtype} for infinite bounds")
198 
199 
200 def get_precision(dtype):
201     if np.issubdtype(dtype, np.floating):
202         return np.finfo(dtype).precision
203     else:
204         return np.inf
205
```
--- 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/gym/spaces/box.py b/gym/spaces/box.py
--- a/gym/spaces/box.py
+++ b/gym/spaces/box.py
@@ -4,6 +4,17 @@
 from gym import logger
 
 
+def _short_repr(arr):
+    """Create a shortened string representation of a numpy array.
+
+    If arr is a multiple of the all-ones vector, return a string representation of the multiplier.
+    Otherwise, return a string representation of the entire array.
+    """
+    if arr.size != 0 and np.min(arr) == np.max(arr):
+        return str(np.min(arr))
+    return str(arr)
+
+
 class Box(Space):
     """
     A (possibly unbounded) box in R^n. Specifically, a Box represents the
@@ -74,6 +85,9 @@
         self.low = self.low.astype(self.dtype)
         self.high = self.high.astype(self.dtype)
 
+        self.low_repr = _short_repr(self.low)
+        self.high_repr = _short_repr(self.high)
+
         # Boolean arrays which indicate the interval type for each coordinate
         self.bounded_below = -np.inf < self.low
         self.bounded_above = np.inf > self.high
@@ -154,7 +168,7 @@
         return [np.asarray(sample) for sample in sample_n]
 
     def __repr__(self):
-        return f"Box({self.low}, {self.high}, {self.shape}, {self.dtype})"
+        return f"Box({self.low_repr}, {self.high_repr}, {self.shape}, {self.dtype})"
 
     def __eq__(self, other):
         return (

{"golden_diff": "diff --git a/gym/spaces/box.py b/gym/spaces/box.py\n--- a/gym/spaces/box.py\n+++ b/gym/spaces/box.py\n@@ -4,6 +4,17 @@\n from gym import logger\n \n \n+def _short_repr(arr):\n+    \"\"\"Create a shortened string representation of a numpy array.\n+\n+    If arr is a multiple of the all-ones vector, return a string representation of the multiplier.\n+    Otherwise, return a string representation of the entire array.\n+    \"\"\"\n+    if arr.size != 0 and np.min(arr) == np.max(arr):\n+        return str(np.min(arr))\n+    return str(arr)\n+\n+\n class Box(Space):\n     \"\"\"\n     A (possibly unbounded) box in R^n. Specifically, a Box represents the\n@@ -74,6 +85,9 @@\n         self.low = self.low.astype(self.dtype)\n         self.high = self.high.astype(self.dtype)\n \n+        self.low_repr = _short_repr(self.low)\n+        self.high_repr = _short_repr(self.high)\n+\n         # Boolean arrays which indicate the interval type for each coordinate\n         self.bounded_below = -np.inf < self.low\n         self.bounded_above = np.inf > self.high\n@@ -154,7 +168,7 @@\n         return [np.asarray(sample) for sample in sample_n]\n \n     def __repr__(self):\n-        return f\"Box({self.low}, {self.high}, {self.shape}, {self.dtype})\"\n+        return f\"Box({self.low_repr}, {self.high_repr}, {self.shape}, {self.dtype})\"\n \n     def __eq__(self, other):\n         return (\n", "issue": "[Proposal] Simplify the Box string representation\n### Proposal \r\n\r\nStop the `Box` string representation from printing out all the low/high values if they are all identical\r\n\r\n### Motivation\r\n\r\nIn any reasonably large environment, `print(env.observation_space)` will spam the output with dozens of zero's or infs or whatever else. This information may be relevant if some of these values are different, but often is not necessary, and is just noise. And good luck printing a Dictionary observation space.\r\n\r\nI think it'd be enough to change the __repr__ method on Box so that if `len(set(self.low)) == 1`, we just print the unique value, and the same thing for `self.high`.\r\n\r\n### Pitch\r\n\r\nMake Boxes printable again\r\n\r\n### Alternatives\r\n\r\nGrin and bear it\r\n\r\n### Additional context\r\n\r\n![image](https://user-images.githubusercontent.com/19414946/143067427-b2b999ba-e430-458a-81c3-f633db2a7b8f.png)\r\nHelp\r\n\r\nThis is partially going back on #2182 and #2183 , but I wasn't around to yell alarm at the full consequences of that PR. But since it will only simplify the representation when all limits are equal, it doesn't actually cause that same problem.\r\n\r\n### Checklist\r\n\r\n- [x] I have checked that there is no similar [issue](https://github.com/openai/gym/issues) in the repo (**required**)\r\n\n", "before_files": [{"content": "import numpy as np\n\nfrom .space import Space\nfrom gym import logger\n\n\nclass Box(Space):\n    \"\"\"\n    A (possibly unbounded) box in R^n. Specifically, a Box represents the\n    Cartesian product of n closed intervals. Each interval has the form of one\n    of [a, b], (-oo, b], [a, oo), or (-oo, oo).\n\n    There are two common use cases:\n\n    * Identical bound for each dimension::\n        >>> Box(low=-1.0, high=2.0, shape=(3, 4), dtype=np.float32)\n        Box(3, 4)\n\n    * Independent bound for each dimension::\n        >>> Box(low=np.array([-1.0, -2.0]), high=np.array([2.0, 4.0]), dtype=np.float32)\n        Box(2,)\n\n    \"\"\"\n\n    def __init__(self, low, high, shape=None, dtype=np.float32, seed=None):\n        assert dtype is not None, \"dtype must be explicitly provided. \"\n        self.dtype = np.dtype(dtype)\n\n        # determine shape if it isn't provided directly\n        if shape is not None:\n            shape = tuple(shape)\n            assert (\n                np.isscalar(low) or low.shape == shape\n            ), \"low.shape doesn't match provided shape\"\n            assert (\n                np.isscalar(high) or high.shape == shape\n            ), \"high.shape doesn't match provided shape\"\n        elif not np.isscalar(low):\n            shape = low.shape\n            assert (\n                np.isscalar(high) or high.shape == shape\n            ), \"high.shape doesn't match low.shape\"\n        elif not np.isscalar(high):\n            shape = high.shape\n            assert (\n                np.isscalar(low) or low.shape == shape\n            ), \"low.shape doesn't match high.shape\"\n        else:\n            raise ValueError(\n                \"shape must be provided or inferred from the shapes of low or high\"\n            )\n\n        # handle infinite bounds and broadcast at the same time if needed\n        if np.isscalar(low):\n            low = get_inf(dtype, \"-\") if np.isinf(low) else low\n            low = np.full(shape, low, dtype=dtype)\n        else:\n            if np.any(np.isinf(low)):\n                # create new array with dtype, but maintain old one to preserve np.inf\n                temp_low = low.astype(dtype)\n                temp_low[np.isinf(low)] = get_inf(dtype, \"-\")\n                low = temp_low\n\n        if np.isscalar(high):\n            high = get_inf(dtype, \"+\") if np.isinf(high) else high\n            high = np.full(shape, high, dtype=dtype)\n        else:\n            if np.any(np.isinf(high)):\n                # create new array with dtype, but maintain old one to preserve np.inf\n                temp_high = high.astype(dtype)\n                temp_high[np.isinf(high)] = get_inf(dtype, \"+\")\n                high = temp_high\n\n        self._shape = shape\n        self.low = low\n        self.high = high\n\n        low_precision = get_precision(self.low.dtype)\n        high_precision = get_precision(self.high.dtype)\n        dtype_precision = get_precision(self.dtype)\n        if min(low_precision, high_precision) > dtype_precision:\n            logger.warn(f\"Box bound precision lowered by casting to {self.dtype}\")\n        self.low = self.low.astype(self.dtype)\n        self.high = self.high.astype(self.dtype)\n\n        # Boolean arrays which indicate the interval type for each coordinate\n        self.bounded_below = -np.inf < self.low\n        self.bounded_above = np.inf > self.high\n\n        super().__init__(self.shape, self.dtype, seed)\n\n    def is_bounded(self, manner=\"both\"):\n        below = np.all(self.bounded_below)\n        above = np.all(self.bounded_above)\n        if manner == \"both\":\n            return below and above\n        elif manner == \"below\":\n            return below\n        elif manner == \"above\":\n            return above\n        else:\n            raise ValueError(\"manner is not in {'below', 'above', 'both'}\")\n\n    def sample(self):\n        \"\"\"\n        Generates a single random sample inside of the Box.\n\n        In creating a sample of the box, each coordinate is sampled according to\n        the form of the interval:\n\n        * [a, b] : uniform distribution\n        * [a, oo) : shifted exponential distribution\n        * (-oo, b] : shifted negative exponential distribution\n        * (-oo, oo) : normal distribution\n        \"\"\"\n        high = self.high if self.dtype.kind == \"f\" else self.high.astype(\"int64\") + 1\n        sample = np.empty(self.shape)\n\n        # Masking arrays which classify the coordinates according to interval\n        # type\n        unbounded = ~self.bounded_below & ~self.bounded_above\n        upp_bounded = ~self.bounded_below & self.bounded_above\n        low_bounded = self.bounded_below & ~self.bounded_above\n        bounded = self.bounded_below & self.bounded_above\n\n        # Vectorized sampling by interval type\n        sample[unbounded] = self.np_random.normal(size=unbounded[unbounded].shape)\n\n        sample[low_bounded] = (\n            self.np_random.exponential(size=low_bounded[low_bounded].shape)\n            + self.low[low_bounded]\n        )\n\n        sample[upp_bounded] = (\n            -self.np_random.exponential(size=upp_bounded[upp_bounded].shape)\n            + self.high[upp_bounded]\n        )\n\n        sample[bounded] = self.np_random.uniform(\n            low=self.low[bounded], high=high[bounded], size=bounded[bounded].shape\n        )\n        if self.dtype.kind == \"i\":\n            sample = np.floor(sample)\n\n        return sample.astype(self.dtype)\n\n    def contains(self, x):\n        if not isinstance(x, np.ndarray):\n            logger.warn(\"Casting input x to numpy array.\")\n            x = np.asarray(x, dtype=self.dtype)\n\n        return (\n            np.can_cast(x.dtype, self.dtype)\n            and x.shape == self.shape\n            and np.all(x >= self.low)\n            and np.all(x <= self.high)\n        )\n\n    def to_jsonable(self, sample_n):\n        return np.array(sample_n).tolist()\n\n    def from_jsonable(self, sample_n):\n        return [np.asarray(sample) for sample in sample_n]\n\n    def __repr__(self):\n        return f\"Box({self.low}, {self.high}, {self.shape}, {self.dtype})\"\n\n    def __eq__(self, other):\n        return (\n            isinstance(other, Box)\n            and (self.shape == other.shape)\n            and np.allclose(self.low, other.low)\n            and np.allclose(self.high, other.high)\n        )\n\n\ndef get_inf(dtype, sign):\n    \"\"\"Returns an infinite that doesn't break things.\n    `dtype` must be an `np.dtype`\n    `bound` must be either `min` or `max`\n    \"\"\"\n    if np.dtype(dtype).kind == \"f\":\n        if sign == \"+\":\n            return np.inf\n        elif sign == \"-\":\n            return -np.inf\n        else:\n            raise TypeError(f\"Unknown sign {sign}, use either '+' or '-'\")\n    elif np.dtype(dtype).kind == \"i\":\n        if sign == \"+\":\n            return np.iinfo(dtype).max - 2\n        elif sign == \"-\":\n            return np.iinfo(dtype).min + 2\n        else:\n            raise TypeError(f\"Unknown sign {sign}, use either '+' or '-'\")\n    else:\n        raise ValueError(f\"Unknown dtype {dtype} for infinite bounds\")\n\n\ndef get_precision(dtype):\n    if np.issubdtype(dtype, np.floating):\n        return np.finfo(dtype).precision\n    else:\n        return np.inf\n", "path": "gym/spaces/box.py"}], "after_files": [{"content": "import numpy as np\n\nfrom .space import Space\nfrom gym import logger\n\n\ndef _short_repr(arr):\n    \"\"\"Create a shortened string representation of a numpy array.\n\n    If arr is a multiple of the all-ones vector, return a string representation of the multiplier.\n    Otherwise, return a string representation of the entire array.\n    \"\"\"\n    if arr.size != 0 and np.min(arr) == np.max(arr):\n        return str(np.min(arr))\n    return str(arr)\n\n\nclass Box(Space):\n    \"\"\"\n    A (possibly unbounded) box in R^n. Specifically, a Box represents the\n    Cartesian product of n closed intervals. Each interval has the form of one\n    of [a, b], (-oo, b], [a, oo), or (-oo, oo).\n\n    There are two common use cases:\n\n    * Identical bound for each dimension::\n        >>> Box(low=-1.0, high=2.0, shape=(3, 4), dtype=np.float32)\n        Box(3, 4)\n\n    * Independent bound for each dimension::\n        >>> Box(low=np.array([-1.0, -2.0]), high=np.array([2.0, 4.0]), dtype=np.float32)\n        Box(2,)\n\n    \"\"\"\n\n    def __init__(self, low, high, shape=None, dtype=np.float32, seed=None):\n        assert dtype is not None, \"dtype must be explicitly provided. \"\n        self.dtype = np.dtype(dtype)\n\n        # determine shape if it isn't provided directly\n        if shape is not None:\n            shape = tuple(shape)\n            assert (\n                np.isscalar(low) or low.shape == shape\n            ), \"low.shape doesn't match provided shape\"\n            assert (\n                np.isscalar(high) or high.shape == shape\n            ), \"high.shape doesn't match provided shape\"\n        elif not np.isscalar(low):\n            shape = low.shape\n            assert (\n                np.isscalar(high) or high.shape == shape\n            ), \"high.shape doesn't match low.shape\"\n        elif not np.isscalar(high):\n            shape = high.shape\n            assert (\n                np.isscalar(low) or low.shape == shape\n            ), \"low.shape doesn't match high.shape\"\n        else:\n            raise ValueError(\n                \"shape must be provided or inferred from the shapes of low or high\"\n            )\n\n        if np.isscalar(low):\n            low = np.full(shape, low, dtype=dtype)\n\n        if np.isscalar(high):\n            high = np.full(shape, high, dtype=dtype)\n\n        self._shape = shape\n        self.low = low\n        self.high = high\n\n        def _get_precision(dtype):\n            if np.issubdtype(dtype, np.floating):\n                return np.finfo(dtype).precision\n            else:\n                return np.inf\n\n        low_precision = _get_precision(self.low.dtype)\n        high_precision = _get_precision(self.high.dtype)\n        dtype_precision = _get_precision(self.dtype)\n        if min(low_precision, high_precision) > dtype_precision:\n            logger.warn(f\"Box bound precision lowered by casting to {self.dtype}\")\n        self.low = self.low.astype(self.dtype)\n        self.high = self.high.astype(self.dtype)\n\n        self.low_repr = _short_repr(self.low)\n        self.high_repr = _short_repr(self.high)\n\n        # Boolean arrays which indicate the interval type for each coordinate\n        self.bounded_below = -np.inf < self.low\n        self.bounded_above = np.inf > self.high\n\n        super().__init__(self.shape, self.dtype, seed)\n\n    def is_bounded(self, manner=\"both\"):\n        below = np.all(self.bounded_below)\n        above = np.all(self.bounded_above)\n        if manner == \"both\":\n            return below and above\n        elif manner == \"below\":\n            return below\n        elif manner == \"above\":\n            return above\n        else:\n            raise ValueError(\"manner is not in {'below', 'above', 'both'}\")\n\n    def sample(self):\n        \"\"\"\n        Generates a single random sample inside of the Box.\n\n        In creating a sample of the box, each coordinate is sampled according to\n        the form of the interval:\n\n        * [a, b] : uniform distribution\n        * [a, oo) : shifted exponential distribution\n        * (-oo, b] : shifted negative exponential distribution\n        * (-oo, oo) : normal distribution\n        \"\"\"\n        high = self.high if self.dtype.kind == \"f\" else self.high.astype(\"int64\") + 1\n        sample = np.empty(self.shape)\n\n        # Masking arrays which classify the coordinates according to interval\n        # type\n        unbounded = ~self.bounded_below & ~self.bounded_above\n        upp_bounded = ~self.bounded_below & self.bounded_above\n        low_bounded = self.bounded_below & ~self.bounded_above\n        bounded = self.bounded_below & self.bounded_above\n\n        # Vectorized sampling by interval type\n        sample[unbounded] = self.np_random.normal(size=unbounded[unbounded].shape)\n\n        sample[low_bounded] = (\n            self.np_random.exponential(size=low_bounded[low_bounded].shape)\n            + self.low[low_bounded]\n        )\n\n        sample[upp_bounded] = (\n            -self.np_random.exponential(size=upp_bounded[upp_bounded].shape)\n            + self.high[upp_bounded]\n        )\n\n        sample[bounded] = self.np_random.uniform(\n            low=self.low[bounded], high=high[bounded], size=bounded[bounded].shape\n        )\n        if self.dtype.kind == \"i\":\n            sample = np.floor(sample)\n\n        return sample.astype(self.dtype)\n\n    def contains(self, x):\n        if not isinstance(x, np.ndarray):\n            logger.warn(\"Casting input x to numpy array.\")\n            x = np.asarray(x, dtype=self.dtype)\n\n        return (\n            np.can_cast(x.dtype, self.dtype)\n            and x.shape == self.shape\n            and np.all(x >= self.low)\n            and np.all(x <= self.high)\n        )\n\n    def to_jsonable(self, sample_n):\n        return np.array(sample_n).tolist()\n\n    def from_jsonable(self, sample_n):\n        return [np.asarray(sample) for sample in sample_n]\n\n    def __repr__(self):\n        return f\"Box({self.low_repr}, {self.high_repr}, {self.shape}, {self.dtype})\"\n\n    def __eq__(self, other):\n        return (\n            isinstance(other, Box)\n            and (self.shape == other.shape)\n            and np.allclose(self.low, other.low)\n            and np.allclose(self.high, other.high)\n        )\n", "path": "gym/spaces/box.py"}]}