Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Farama Foundation Gymnasium MultiDiscrete Space

From Leeroopedia
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

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

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment