Implementation:Farama Foundation Gymnasium Tuple 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 spaces as a fixed-length tuple provided by Gymnasium.
Description
The Tuple space represents the cartesian product of a sequence of Space instances. Each sample is a Python tuple where the i-th element is independently drawn from the i-th sub-space. The number and types of sub-spaces are fixed at construction time.
The class also implements Python's typing.Sequence protocol, meaning it supports indexing (space[i]) and length (len(space)).
The space is numpy-flattenable (is_np_flattenable returns True) only if all constituent sub-spaces are flattenable. When flattenable, the flatten utility concatenates the flattened sub-space samples into a single 1D array. When not flattenable (e.g., contains a Graph or Sequence sub-space), flatten returns a tuple of individually flattened sub-samples.
Usage
Use Tuple when the observation or action consists of a fixed collection of heterogeneous components that should be sampled together. For example, an environment that returns both a continuous observation (Box) and a discrete status flag (Discrete) can use Tuple((Box(...), Discrete(...))).
Code Reference
Source Location
- Repository: Farama_Foundation_Gymnasium
- File:
gymnasium/spaces/tuple.py
Signature
class Tuple(Space[tuple[Any, ...]], typing.Sequence[Any]):
def __init__(
self,
spaces: Iterable[Space[Any]],
seed: int | typing.Sequence[int] | np.random.Generator | None = None,
)
Import
from gymnasium.spaces import Tuple
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| spaces | Iterable[Space] |
Yes | The sequence of sub-spaces forming the cartesian product. Each element must be a Space instance.
|
| seed | int, Sequence[int], np.random.Generator, or None |
No | Optional seed. An int seeds the Tuple space which then generates sub-seeds. A list/tuple of ints must match the number of sub-spaces and seeds each one directly. |
Outputs
| Name | Type | Description |
|---|---|---|
| sample() returns | tuple[Any, ...] |
A tuple where each element is an independent sample from the corresponding sub-space. |
| contains() returns | bool |
Whether a given value is a tuple of the correct length where each element is contained in the corresponding sub-space. |
Key Methods
| Method | Description |
|---|---|
sample(mask=None, probability=None) |
Generate a random tuple by independently sampling each sub-space. Mask/probability must be a tuple matching the number of sub-spaces. |
contains(x) |
Check that x is a tuple (or list/ndarray promoted to tuple) with the correct length and each element belongs to its sub-space.
|
seed(seed) |
Seed the PRNG. Accepts None (random), int (generates sub-seeds), or a list/tuple of ints (one per sub-space).
|
__getitem__(index) |
Access a sub-space by index. |
__len__() |
Returns the number of sub-spaces. |
to_jsonable(sample_n) |
Convert a batch of tuple samples to JSON-serializable format. Each sub-space serializes its own components. |
from_jsonable(sample_n) |
Convert JSON-serializable data back to a list of tuples. |
Usage Examples
from gymnasium.spaces import Tuple, Box, Discrete
import numpy as np
# Observation: continuous position + discrete mode
space = Tuple((Box(-1, 1, shape=(2,)), Discrete(3)), seed=42)
sample = space.sample()
print(sample)
# e.g. (array([-0.39, 0.21], dtype=float32), np.int64(2))
# Access sub-spaces
print(space[0]) # Box(-1.0, 1.0, (2,), float32)
print(space[1]) # Discrete(3)
print(len(space)) # 2
# Masked sampling
mask = (
None, # no mask for Box
np.array([1, 0, 1], dtype=np.int8), # mask for Discrete (only 0 or 2)
)
masked = space.sample(mask=mask)
print(masked[1]) # 0 or 2
# Seeding with per-subspace seeds
space.seed([42, 123])
s1 = space.sample()
space.seed([42, 123])
s2 = space.sample()
# s1 and s2 are identical
# Membership check
valid = (np.array([0.5, -0.5], dtype=np.float32), np.int64(1))
print(valid in space) # True
invalid = (np.array([0.5, -0.5], dtype=np.float32), np.int64(5))
print(invalid in space) # False (5 not in Discrete(3))
# Nested Tuple spaces
nested = Tuple((
Tuple((Discrete(2), Discrete(3))),
Box(0, 1, shape=(4,))
))
nested_sample = nested.sample()
print(type(nested_sample)) # <class 'tuple'>
print(type(nested_sample[0])) # <class 'tuple'>
Related Pages
- Environment:Farama_Foundation_Gymnasium_Python_3_10_Runtime
- Farama_Foundation_Gymnasium_Space_Base -- abstract base class for all spaces
- Farama_Foundation_Gymnasium_OneOf_Space -- exclusive union (samples from exactly one sub-space)
- Farama_Foundation_Gymnasium_Sequence_Space -- variable-length sequence of elements from one space
- Farama_Foundation_Gymnasium_Space_Utils -- flatten/unflatten utilities (concatenates sub-space arrays when flattenable)