Files
Gymnasium/gymnasium/spaces/multi_binary.py

126 lines
4.7 KiB
Python
Raw Normal View History

"""Implementation of a space that consists of binary np.ndarrays of a fixed shape."""
from __future__ import annotations
from typing import Any, Sequence
import numpy as np
import numpy.typing as npt
from gymnasium.spaces.space import MaskNDArray, Space
class MultiBinary(Space[npt.NDArray[np.int8]]):
"""An n-shape binary space.
Elements of this space are binary arrays of a shape that is fixed during construction.
Example Usage::
>>> observation_space = MultiBinary(5, seed=42)
Pydocstyle utils vector docstring (#2788) * Added pydocstyle to pre-commit * Added docstrings for tests and updated the tests for autoreset * Add pydocstyle exclude folder to allow slowly adding new docstrings * Add docstrings for setup.py and gym/__init__.py, core.py, error.py and logger.py * Check that all unwrapped environment are of a particular wrapper type * Reverted back to import gym.spaces.Space to gym.spaces * Fixed the __init__.py docstring * Fixed autoreset autoreset test * Updated gym __init__.py top docstring * Fix examples in docstrings * Add docstrings and type hints where known to all functions and classes in gym/utils and gym/vector * Remove unnecessary import * Removed "unused error" and make APIerror deprecated at gym 1.0 * Add pydocstyle description to CONTRIBUTING.md * Added docstrings section to CONTRIBUTING.md * Added :meth: and :attr: keywords to docstrings * Added :meth: and :attr: keywords to docstrings * Imported annotations from __future__ to fix python 3.7 * Add __future__ import annotations for python 3.7 * isort * Remove utils and vectors for this PR and spaces for previous PR * Update gym/envs/classic_control/acrobot.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/envs/classic_control/acrobot.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/envs/classic_control/acrobot.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/spaces/dict.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/env_checker.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/env_checker.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/env_checker.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/env_checker.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/env_checker.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/ezpickle.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/ezpickle.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/play.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Pre-commit * Updated docstrings with :meth: * Updated docstrings with :meth: * Update gym/utils/play.py * Update gym/utils/play.py * Update gym/utils/play.py * Apply suggestions from code review Co-authored-by: Markus Krimmel <montcyril@gmail.com> * pre-commit * Update gym/utils/play.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Updated fps and zoom parameter docstring * Update play docstring * Apply suggestions from code review Added suggested corrections from @markus28 Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Pre-commit magic * Update the `gym.make` docstring with a warning for `env_checker` * Updated and fixed vector docstrings * Update test names for reflect the project filename style Co-authored-by: Markus Krimmel <montcyril@gmail.com>
2022-05-20 14:49:30 +01:00
>>> observation_space.sample()
array([1, 0, 1, 0, 1], dtype=int8)
>>> observation_space = MultiBinary([3, 2], seed=42)
Pydocstyle utils vector docstring (#2788) * Added pydocstyle to pre-commit * Added docstrings for tests and updated the tests for autoreset * Add pydocstyle exclude folder to allow slowly adding new docstrings * Add docstrings for setup.py and gym/__init__.py, core.py, error.py and logger.py * Check that all unwrapped environment are of a particular wrapper type * Reverted back to import gym.spaces.Space to gym.spaces * Fixed the __init__.py docstring * Fixed autoreset autoreset test * Updated gym __init__.py top docstring * Fix examples in docstrings * Add docstrings and type hints where known to all functions and classes in gym/utils and gym/vector * Remove unnecessary import * Removed "unused error" and make APIerror deprecated at gym 1.0 * Add pydocstyle description to CONTRIBUTING.md * Added docstrings section to CONTRIBUTING.md * Added :meth: and :attr: keywords to docstrings * Added :meth: and :attr: keywords to docstrings * Imported annotations from __future__ to fix python 3.7 * Add __future__ import annotations for python 3.7 * isort * Remove utils and vectors for this PR and spaces for previous PR * Update gym/envs/classic_control/acrobot.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/envs/classic_control/acrobot.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/envs/classic_control/acrobot.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/spaces/dict.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/env_checker.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/env_checker.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/env_checker.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/env_checker.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/env_checker.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/ezpickle.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/ezpickle.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Update gym/utils/play.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Pre-commit * Updated docstrings with :meth: * Updated docstrings with :meth: * Update gym/utils/play.py * Update gym/utils/play.py * Update gym/utils/play.py * Apply suggestions from code review Co-authored-by: Markus Krimmel <montcyril@gmail.com> * pre-commit * Update gym/utils/play.py Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Updated fps and zoom parameter docstring * Update play docstring * Apply suggestions from code review Added suggested corrections from @markus28 Co-authored-by: Markus Krimmel <montcyril@gmail.com> * Pre-commit magic * Update the `gym.make` docstring with a warning for `env_checker` * Updated and fixed vector docstrings * Update test names for reflect the project filename style Co-authored-by: Markus Krimmel <montcyril@gmail.com>
2022-05-20 14:49:30 +01:00
>>> observation_space.sample()
array([[1, 0],
[1, 0],
[1, 1]], dtype=int8)
2021-07-29 02:26:34 +02:00
"""
def __init__(
Fixed batch spaces where the original space's seed was ignored. Issue 2680 (#2727) * Add a case for the Box shape where the low and high values are both scalars * Add seeding.RandomNumberGenerator parameter to Dict seed. Modify __repr__ for the dictionary space string looks similar to an actual dictionary * Add seeding.RandomNumberGenerator parameter to Multi Binary seed * Add seeding.RandomNumberGenerator parameter to Multi Binary seed. Modify nvec typing to include np.ndarray * Space seed typing can be a seeding.RandomNumberGenerator. If a seeding.RNG is provided then it is assigned to _np_random and .seed is not run * Fixed the tuple seeding type as List[int] is not a valid Space seed type * Added typing to batch_space. The batch_space seed is equal to the space's seeding * Fixed the seeding type * Add test for batch space seeds are identical to the original space's seeding * Add equivalence function for RandomNumberGenerator comparing the bit_generator.state * The batch_space functions uses a copy of the seed for the original space * Set the action space seed for sync_vector_env seed testing * Add test for the seeding of the sync vector environment * Update the test_batch_space_seed to check the resulting sampling are equivalent for testing * Revert representation back to the original version * Remove additional Box shape initialisation * Remove additional typing of MultiDiscrete * Fixed bug of Space batch space where the original space's np_random is not a complete copy of the original space * Add CustomSpace to the batched space seed test * Modify the CustomSpace sample to produce a random number not a static value * Fix CustomSpace to reflect the sample function * Copy the space.np_random for the batched_space seed to ensure that the original space doesn't sampling doesn't effect the batched_space * Parameterized the batch_space_seed, added testing for rng_different_at_each_index and test_deterministic * Black and isort pre-commit changes * Pre-commit fix * MacOS, test_read_from_shared_memory throws an error that the inner _process_write function was unpicklable. Making the function a top-level function solves this error * Fixed typing of seed where a space's seed function differs from Space.seed's typing * Added check that the sample lengths are equal and explicitly provided the number of batched spaces n=1 * Removed relative imports for absolute imports * Use deepcopy instead of copy * Replaces `from numpy.testing._private.utils import assert_array_equal` with `from numpy.testing import assert_array_equal` * Using the seeding `__eq__` function, replace `np_random.bit_generator.state` with `np_random` * Added docstrings and comments to the tests to explain their purpose * Remove __eq__ from RandomNumberGenerator and add to tests/vector/utils * Add sync vector determinism test for issue #2680 * Fixed bug for https://github.com/openai/gym/pull/2727/files/462101d3846bc35ff3fad9f65979c693472a93a8#r850740825 * Made the new seeds a list of integers
2022-04-24 17:14:33 +01:00
self,
n: npt.NDArray[np.integer[Any]] | Sequence[int] | int,
seed: int | np.random.Generator | None = None,
):
"""Constructor of :class:`MultiBinary` space.
Args:
n: This will fix the shape of elements of the space. It can either be an integer (if the space is flat)
or some sort of sequence (tuple, list or np.ndarray) if there are multiple axes.
seed: Optionally, you can use this argument to seed the RNG that is used to sample from the space.
"""
if isinstance(n, (Sequence, np.ndarray)):
self.n = input_n = tuple(int(i) for i in n)
2022-04-11 13:27:23 -04:00
assert (np.asarray(input_n) > 0).all() # n (counts) have to be positive
else:
self.n = n = int(n)
2021-07-29 02:26:34 +02:00
input_n = (n,)
2022-04-11 13:27:23 -04:00
assert (np.asarray(input_n) > 0).all() # n (counts) have to be positive
super().__init__(input_n, np.int8, seed)
@property
def shape(self) -> tuple[int, ...]:
"""Has stricter type than gym.Space - never None."""
return self._shape # type: ignore
@property
def is_np_flattenable(self):
"""Checks whether this space can be flattened to a :class:`spaces.Box`."""
return True
def sample(self, mask: MaskNDArray | None = None) -> npt.NDArray[np.int8]:
"""Generates a single random sample from this space.
A sample is drawn by independent, fair coin tosses (one toss per binary variable of the space).
Args:
mask: An optional np.ndarray to mask samples with expected shape of ``space.shape``.
For mask == 0 then the samples will be 0 and mask == 1 then random samples will be generated.
The expected mask shape is the space shape and mask dtype is `np.int8`.
Returns:
Sampled values from space
"""
if mask is not None:
assert isinstance(
mask, np.ndarray
), f"The expected type of the mask is np.ndarray, actual type: {type(mask)}"
assert (
mask.dtype == np.int8
), f"The expected dtype of the mask is np.int8, actual dtype: {mask.dtype}"
assert (
mask.shape == self.shape
), f"The expected shape of the mask is {self.shape}, actual shape: {mask.shape}"
assert np.all(
(mask == 0) | (mask == 1) | (mask == 2)
), f"All values of a mask should be 0, 1 or 2, actual values: {mask}"
return np.where(
mask == 2,
self.np_random.integers(low=0, high=2, size=self.n, dtype=self.dtype),
mask.astype(self.dtype),
)
Seeding update (#2422) * Ditch most of the seeding.py and replace np_random with the numpy default_rng. Let's see if tests pass * Updated a bunch of RNG calls from the RandomState API to Generator API * black; didn't expect that, did ya? * Undo a typo * blaaack * More typo fixes * Fixed setting/getting state in multidiscrete spaces * Fix typo, fix a test to work with the new sampling * Correctly (?) pass the randomly generated seed if np_random is called with None as seed * Convert the Discrete sample to a python int (as opposed to np.int64) * Remove some redundant imports * First version of the compatibility layer for old-style RNG. Mainly to trigger tests. * Removed redundant f-strings * Style fixes, removing unused imports * Try to make tests pass by removing atari from the dockerfile * Try to make tests pass by removing atari from the setup * Try to make tests pass by removing atari from the setup * Try to make tests pass by removing atari from the setup * First attempt at deprecating `env.seed` and supporting `env.reset(seed=seed)` instead. Tests should hopefully pass but throw up a million warnings. * black; didn't expect that, didya? * Rename the reset parameter in VecEnvs back to `seed` * Updated tests to use the new seeding method * Removed a bunch of old `seed` calls. Fixed a bug in AsyncVectorEnv * Stop Discrete envs from doing part of the setup (and using the randomness) in init (as opposed to reset) * Add explicit seed to wrappers reset * Remove an accidental return * Re-add some legacy functions with a warning. * Use deprecation instead of regular warnings for the newly deprecated methods/functions
2021-12-08 22:14:15 +01:00
return self.np_random.integers(low=0, high=2, size=self.n, dtype=self.dtype)
def contains(self, x: Any) -> bool:
"""Return boolean specifying if x is a valid member of this space."""
if isinstance(x, Sequence):
2019-04-19 14:09:44 -07:00
x = np.array(x) # Promote list to array for contains check
return bool(
isinstance(x, np.ndarray)
and self.shape == x.shape
and np.all(np.logical_or(x == 0, x == 1))
)
def to_jsonable(
self, sample_n: Sequence[npt.NDArray[np.int8]]
) -> list[Sequence[int]]:
"""Convert a batch of samples from this space to a JSONable data type."""
return np.array(sample_n).tolist()
def from_jsonable(
self, sample_n: list[Sequence[int]]
) -> list[npt.NDArray[np.int8]]:
"""Convert a JSONable data type to a batch of samples from this space."""
return [np.asarray(sample, self.dtype) for sample in sample_n]
def __repr__(self) -> str:
"""Gives a string representation of this space."""
return f"MultiBinary({self.n})"
def __eq__(self, other: Any) -> bool:
"""Check whether `other` is equivalent to this instance."""
return isinstance(other, MultiBinary) and self.n == other.n