Implementation:Farama Foundation Gymnasium MultiDiscrete Space
| Knowledge Sources | |
|---|---|
| Domains | Reinforcement_Learning, Spaces |
| Last Updated | 2026-02-15 03:00 GMT |
Overview
Concrete tool for representing the cartesian product of multiple discrete action or observation variables provided by Gymnasium.
Description
The MultiDiscrete space represents the cartesian product of arbitrary Discrete spaces. Each element of the resulting array is an independent categorical variable that can take on a different number of values. The number of categories for each variable is specified by the nvec parameter, and an optional start parameter shifts the minimum value of each variable (defaulting to 0).
For example, a game controller with an arrow key (5 directions), button A (2 states), and button B (2 states) can be represented as MultiDiscrete([5, 2, 2]). Samples are integer arrays where each element is independently drawn uniformly from its respective range.
The space supports multi-dimensional nvec arrays (e.g., a 2D grid of discrete variables) and is numpy-flattenable (is_np_flattenable returns True). When flattened, each categorical variable becomes a one-hot encoded segment, and these segments are concatenated.
Usage
Use MultiDiscrete when the action or observation consists of multiple independent categorical variables, each potentially having a different number of categories. Common applications include game controllers, multi-agent discrete action spaces, and grid-based environments with multiple decision dimensions.
Code Reference
Source Location
- Repository: Farama_Foundation_Gymnasium
- File:
gymnasium/spaces/multi_discrete.py
Signature
class MultiDiscrete(Space[NDArray[np.integer]]):
def __init__(
self,
nvec: NDArray[np.integer[Any]] | list[int],
dtype: str | type[np.integer[Any]] = np.int64,
seed: int | np.random.Generator | None = None,
start: NDArray[np.integer[Any]] | list[int] | None = None,
)
Import
from gymnasium.spaces import MultiDiscrete
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| nvec | NDArray[np.integer] or list[int] |
Yes | Vector of counts for each categorical variable. All values must be positive. Can be multi-dimensional. |
| dtype | str or type[np.integer] |
No | Integer dtype for the space. Defaults to np.int64.
|
| seed | int, np.random.Generator, or None |
No | Optional seed for the random number generator. |
| start | NDArray[np.integer], list[int], or None |
No | Starting value for each categorical variable. Defaults to 0 for all variables. Must have the same shape as nvec.
|
Outputs
| Name | Type | Description |
|---|---|---|
| sample() returns | NDArray[np.integer] |
An integer array with the same shape as nvec, where each element is in [start, start + nvec).
|
| contains() returns | bool |
Whether a given value is a valid integer array within the defined bounds and shape. |
Key Methods
| Method | Description |
|---|---|
sample(mask=None, probability=None) |
Generate a random sample. Supports mask-based sampling (tuple of int8 arrays, 0/1 per action) and probability-based sampling (tuple of float64 arrays that sum to 1). |
contains(x) |
Verify that x is an integer ndarray with correct shape, dtype compatibility, and values within [start, start + nvec).
|
__getitem__(index) |
Extract a subspace: returns a Discrete space if the indexed element is scalar, otherwise a MultiDiscrete subspace.
|
__len__() |
Returns the length of the first axis of nvec.
|
to_jsonable(sample_n) |
Convert a batch of samples to JSON-serializable lists. |
from_jsonable(sample_n) |
Convert JSON-serializable data back to numpy arrays. |
Usage Examples
from gymnasium.spaces import MultiDiscrete
import numpy as np
# Game controller: arrow keys (5), button A (2), button B (2)
space = MultiDiscrete([5, 2, 2], seed=42)
sample = space.sample()
print(sample) # e.g. array([3, 1, 0])
print(sample.shape) # (3,)
# With custom start values
space_offset = MultiDiscrete([5, 2, 2], start=[1, 0, 0], seed=42)
sample_offset = space_offset.sample()
print(sample_offset) # values in [1,5], [0,1], [0,1]
# Multi-dimensional nvec
space_2d = MultiDiscrete(np.array([[1, 2], [3, 4]]), seed=42)
sample_2d = space_2d.sample()
print(sample_2d.shape) # (2, 2)
# Masked sampling
mask = (
np.array([0, 0, 1, 0, 0], dtype=np.int8), # arrow: only DOWN
np.array([1, 1], dtype=np.int8), # button A: either
np.array([1, 0], dtype=np.int8), # button B: only NOOP
)
masked = space.sample(mask=mask)
print(masked) # array([2, ?, 0]) where ? is 0 or 1
# Subspace extraction
subspace = space[0]
print(subspace) # Discrete(5)
# Membership check
print(np.array([3, 1, 0]) in space) # True
print(np.array([5, 1, 0]) in space) # False (5 >= nvec[0])
Related Pages
- Environment:Farama_Foundation_Gymnasium_Python_3_10_Runtime
- Farama_Foundation_Gymnasium_Space_Base -- abstract base class for all spaces
- Farama_Foundation_Gymnasium_MultiBinary_Space -- binary-only variant
- Farama_Foundation_Gymnasium_Space_Utils -- flatten/unflatten utilities (one-hot encoding for MultiDiscrete)