mirror of
https://github.com/Farama-Foundation/Gymnasium.git
synced 2025-08-27 08:47:08 +00:00
* 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 462101d384 (r850740825)
* Made the new seeds a list of integers
85 lines
3.1 KiB
Python
85 lines
3.1 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Iterable, Optional, Sequence
|
|
|
|
import numpy as np
|
|
|
|
from gym import logger
|
|
from gym.spaces.discrete import Discrete
|
|
from gym.spaces.space import Space
|
|
from gym.utils import seeding
|
|
|
|
|
|
class MultiDiscrete(Space[np.ndarray]):
|
|
"""
|
|
The multi-discrete action space consists of a series of discrete action spaces with different number of actions in each. It is useful to represent game controllers or keyboards where each key can be represented as a discrete action space. It is parametrized by passing an array of positive integers specifying number of actions for each discrete action space.
|
|
|
|
Note:
|
|
|
|
Some environment wrappers assume a value of 0 always represents the NOOP action.
|
|
|
|
e.g. Nintendo Game Controller - Can be conceptualized as 3 discrete action spaces:
|
|
|
|
1. Arrow Keys: Discrete 5 - NOOP[0], UP[1], RIGHT[2], DOWN[3], LEFT[4] - params: min: 0, max: 4
|
|
2. Button A: Discrete 2 - NOOP[0], Pressed[1] - params: min: 0, max: 1
|
|
3. Button B: Discrete 2 - NOOP[0], Pressed[1] - params: min: 0, max: 1
|
|
|
|
It can be initialized as ``MultiDiscrete([ 5, 2, 2 ])``
|
|
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
nvec: list[int],
|
|
dtype=np.int64,
|
|
seed: Optional[int | seeding.RandomNumberGenerator] = None,
|
|
):
|
|
"""
|
|
nvec: vector of counts of each categorical variable
|
|
"""
|
|
self.nvec = np.array(nvec, dtype=dtype, copy=True)
|
|
assert (self.nvec > 0).all(), "nvec (counts) have to be positive"
|
|
|
|
super().__init__(self.nvec.shape, dtype, seed)
|
|
|
|
@property
|
|
def shape(self) -> tuple[int, ...]:
|
|
"""Has stricter type than gym.Space - never None."""
|
|
return self._shape # type: ignore
|
|
|
|
def sample(self) -> np.ndarray:
|
|
return (self.np_random.random(self.nvec.shape) * self.nvec).astype(self.dtype)
|
|
|
|
def contains(self, x) -> bool:
|
|
if isinstance(x, Sequence):
|
|
x = np.array(x) # Promote list to array for contains check
|
|
# if nvec is uint32 and space dtype is uint32, then 0 <= x < self.nvec guarantees that x
|
|
# is within correct bounds for space dtype (even though x does not have to be unsigned)
|
|
return bool(x.shape == self.shape and (0 <= x).all() and (x < self.nvec).all())
|
|
|
|
def to_jsonable(self, sample_n: Iterable[np.ndarray]):
|
|
return [sample.tolist() for sample in sample_n]
|
|
|
|
def from_jsonable(self, sample_n):
|
|
return np.array(sample_n)
|
|
|
|
def __repr__(self):
|
|
return f"MultiDiscrete({self.nvec})"
|
|
|
|
def __getitem__(self, index):
|
|
nvec = self.nvec[index]
|
|
if nvec.ndim == 0:
|
|
subspace = Discrete(nvec)
|
|
else:
|
|
subspace = MultiDiscrete(nvec, self.dtype) # type: ignore
|
|
subspace.np_random.bit_generator.state = self.np_random.bit_generator.state
|
|
return subspace
|
|
|
|
def __len__(self):
|
|
if self.nvec.ndim >= 2:
|
|
logger.warn("Get length of a multi-dimensional MultiDiscrete space.")
|
|
return len(self.nvec)
|
|
|
|
def __eq__(self, other):
|
|
return isinstance(other, MultiDiscrete) and np.all(self.nvec == other.nvec)
|