unienv_interface.space.spaces¶
Space
¶
Space(backend: ComputeBackend[ArrayAPIArray, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT], shape: Optional[Sequence[int]] = None, device: Optional[_SpaceBDeviceT] = None, dtype: Optional[_SpaceBDTypeT] = None)
Bases: ABC, Generic[SpaceDataT, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT]
Abstract description of a valid data domain.
Spaces carry backend, device, shape, and dtype metadata and define the operations needed by the rest of UniEnv: validation, sampling, empty value creation, serialization-friendly representation, and backend/device conversion for both the space definition and its data.
shape
property
¶
shape: tuple[int, ...] | None
Return the shape of the space as an immutable property.
to
abstractmethod
¶
to(backend: Optional[ComputeBackend] = None, device: Optional[Union[_SpaceBDeviceT, Any]] = None) -> Union[Space[SpaceDataT, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT], Space]
Return an equivalent space on another backend and/or device.
sample
abstractmethod
¶
sample(rng: _SpaceBDRNGT, **kwargs) -> Tuple[_SpaceBDRNGT, SpaceDataT]
Draw one valid value from the space and return the advanced RNG.
create_empty
abstractmethod
¶
create_empty() -> SpaceDataT
Create an empty data structure for this space.
is_bounded
abstractmethod
¶
is_bounded(manner: Literal['both', 'below', 'above'] = 'both') -> bool
Return boolean specifying if this space is bounded in the specified manner.
contains
abstractmethod
¶
contains(x: Any) -> bool
Return boolean specifying if x is a valid member of this space.
is_subspaceeq
¶
is_subspaceeq(other: Space) -> bool
Return whether this space is a non-strict subspace of other (self ⊆ other).
A space a is a non-strict subspace of b (a ⊆ b) when every
valid sample of a is also a valid member of b; equality is
allowed, i.e. a == b implies a.is_subspaceeq(b).
The primary use case is a controller that declares its REQUIRED
observation space and checks
required.is_subspaceeq(env_observation_space): for DictSpace
this must hold even when the environment space exposes EXTRA keys
beyond the required ones (unlike DictSpace.contains, which demands
exact key equality). Controller-required-space checks should typically
use is_subspaceeq rather than the strict is_subspace because a
controller's required space may exactly equal the env space.
Comparison policy (structural only):
- The two spaces must share the same backend type.
- Dtypes must be strictly equal; no implicit cast widening is performed.
deviceis intentionally ignored — two spaces on different devices may still be in a subspace relation.
Cross-type comparisons (e.g. BoxSpace vs DictSpace) return
False rather than raising. Subclasses override this method to
provide concrete structural containment checks; the base implementation
raises NotImplementedError to mirror the abstract-method style of
this class.
is_subspace
¶
is_subspace(other: Space) -> bool
Return whether this space is a STRICT subspace of other (self ⊂ other).
Defined uniformly for all spaces as::
self.is_subspace(other) ⟺ self.is_subspaceeq(other) and not other.is_subspaceeq(self)
I.e. self ⊆ other holds but other ⊆ self does not, so self
is a PROPER (strict) subspace of other. This is the ⊂ relation
versus the non-strict ⊆ provided by :meth:is_subspaceeq.
This definition is used instead of relying on __eq__ because some
space classes only have identity __eq__; defining strict
containment via the symmetric non-strict check works uniformly for all
classes regardless of their __eq__ implementation.
For structurally-distinct-but-mutually-containing spaces (which should
not occur under the strict dtype/shape policies enforced by the
per-class is_subspaceeq implementations) this degrades gracefully
to False: if both self.is_subspaceeq(other) and
other.is_subspaceeq(self) hold, the two spaces are considered
equivalent and neither is a STRICT subspace of the other.
If either side's is_subspaceeq is not implemented (the base
:meth:is_subspaceeq raises NotImplementedError), the exception
propagates to the caller — it is NOT swallowed into False so that
callers can tell that the comparison is unsupported.
Note: controller-required-space checks should typically use
:meth:is_subspaceeq (a controller's required space may exactly equal
the env space, in which case the strict is_subspace would return
False).
get_repr
abstractmethod
¶
get_repr(abbreviate: bool = False, include_backend: bool = True, include_device: bool = True, include_dtype: bool = True) -> str
Return a string representation of the space.
data_to
abstractmethod
¶
data_to(data: SpaceDataT, backend: Optional[ComputeBackend] = None, device: Optional[Union[_SpaceBDeviceT, Any]] = None) -> Union[SpaceDataT, Any]
Convert space-compatible data to another backend and/or device.
abbr_device
staticmethod
¶
abbr_device(spaces: Iterable[Space[Any, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT]]) -> Optional[_SpaceBDeviceT]
Return the shared device across spaces, or None if mixed/empty.
BinarySpace
¶
BinarySpace(backend: ComputeBackend[BArrayType, BDeviceType, BDtypeType, BRNGType], shape: Sequence[int], dtype: Optional[BDtypeType] = None, device: Optional[BDeviceType] = None)
Bases: Space[BArrayType, BDeviceType, BDtypeType, BRNGType]
shape
property
¶
shape: tuple[int, ...] | None
Return the shape of the space as an immutable property.
is_subspace
¶
is_subspace(other: Space) -> bool
Return whether this space is a STRICT subspace of other (self ⊂ other).
Defined uniformly for all spaces as::
self.is_subspace(other) ⟺ self.is_subspaceeq(other) and not other.is_subspaceeq(self)
I.e. self ⊆ other holds but other ⊆ self does not, so self
is a PROPER (strict) subspace of other. This is the ⊂ relation
versus the non-strict ⊆ provided by :meth:is_subspaceeq.
This definition is used instead of relying on __eq__ because some
space classes only have identity __eq__; defining strict
containment via the symmetric non-strict check works uniformly for all
classes regardless of their __eq__ implementation.
For structurally-distinct-but-mutually-containing spaces (which should
not occur under the strict dtype/shape policies enforced by the
per-class is_subspaceeq implementations) this degrades gracefully
to False: if both self.is_subspaceeq(other) and
other.is_subspaceeq(self) hold, the two spaces are considered
equivalent and neither is a STRICT subspace of the other.
If either side's is_subspaceeq is not implemented (the base
:meth:is_subspaceeq raises NotImplementedError), the exception
propagates to the caller — it is NOT swallowed into False so that
callers can tell that the comparison is unsupported.
Note: controller-required-space checks should typically use
:meth:is_subspaceeq (a controller's required space may exactly equal
the env space, in which case the strict is_subspace would return
False).
abbr_device
staticmethod
¶
abbr_device(spaces: Iterable[Space[Any, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT]]) -> Optional[_SpaceBDeviceT]
Return the shared device across spaces, or None if mixed/empty.
get_repr
¶
get_repr(abbreviate=False, include_backend=True, include_device=True, include_dtype=True)
is_subspaceeq
¶
is_subspaceeq(other: Any) -> bool
Return whether this binary space is a non-strict subspace of other (⊆).
True iff other is a BinarySpace on the same backend with equal
shape and dtype. Since a binary space contains exactly the boolean
tensors of its shape, two such spaces are in a subspace relation iff
they are structurally identical (modulo device).
BoxSpace
¶
BoxSpace(backend: ComputeBackend[BArrayType, BDeviceType, BDtypeType, BRNGType], low: SupportsFloat | BArrayType, high: SupportsFloat | BArrayType, dtype: BDtypeType, device: Optional[BDeviceType] = None, shape: Optional[Sequence[int]] = None)
Bases: Space[BArrayType, BDeviceType, BDtypeType, BRNGType]
Continuous or integer hyper-rectangle defined by elementwise bounds.
Create a box with broadcastable low and high bounds.
shape
property
¶
shape: tuple[int, ...] | None
Return the shape of the space as an immutable property.
is_subspace
¶
is_subspace(other: Space) -> bool
Return whether this space is a STRICT subspace of other (self ⊂ other).
Defined uniformly for all spaces as::
self.is_subspace(other) ⟺ self.is_subspaceeq(other) and not other.is_subspaceeq(self)
I.e. self ⊆ other holds but other ⊆ self does not, so self
is a PROPER (strict) subspace of other. This is the ⊂ relation
versus the non-strict ⊆ provided by :meth:is_subspaceeq.
This definition is used instead of relying on __eq__ because some
space classes only have identity __eq__; defining strict
containment via the symmetric non-strict check works uniformly for all
classes regardless of their __eq__ implementation.
For structurally-distinct-but-mutually-containing spaces (which should
not occur under the strict dtype/shape policies enforced by the
per-class is_subspaceeq implementations) this degrades gracefully
to False: if both self.is_subspaceeq(other) and
other.is_subspaceeq(self) hold, the two spaces are considered
equivalent and neither is a STRICT subspace of the other.
If either side's is_subspaceeq is not implemented (the base
:meth:is_subspaceeq raises NotImplementedError), the exception
propagates to the caller — it is NOT swallowed into False so that
callers can tell that the comparison is unsupported.
Note: controller-required-space checks should typically use
:meth:is_subspaceeq (a controller's required space may exactly equal
the env space, in which case the strict is_subspace would return
False).
abbr_device
staticmethod
¶
abbr_device(spaces: Iterable[Space[Any, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT]]) -> Optional[_SpaceBDeviceT]
Return the shared device across spaces, or None if mixed/empty.
to
¶
to(backend: Optional[ComputeBackend] = None, device: Optional[Union[BDeviceType, Any]] = None) -> Union[BoxSpace[BArrayType, BDeviceType, BDtypeType, BRNGType], BoxSpace]
Return an equivalent box on another backend and/or device.
sample
¶
sample(rng: BRNGType) -> Tuple[BRNGType, BArrayType]
Generates a single random sample inside the Box.
In creating a sample of the box, each coordinate is sampled (independently) from a distribution that is chosen according to the form of the interval:
- :math:
[a, b]: uniform distribution - :math:
[a, \infty): shifted exponential distribution - :math:
(-\infty, b]: shifted negative exponential distribution - :math:
(-\infty, \infty): normal distribution
Returns:
| Type | Description |
|---|---|
Tuple[BRNGType, BArrayType]
|
A sampled value from the Box |
create_empty
¶
create_empty() -> BArrayType
Allocate an uninitialized array with the box shape and dtype.
clip
¶
clip(x: BArrayType) -> BArrayType
Clip the values of x to be within the bounds of this space.
get_repr
¶
get_repr(abbreviate: bool = False, include_backend: bool = True, include_device: bool = True, include_dtype: bool = True) -> str
is_subspaceeq
¶
is_subspaceeq(other: Any) -> bool
Return whether this box is a non-strict subspace of other (⊆).
True iff other is a BoxSpace on the same backend, with equal
shape and dtype, and other's bounds contain self's bounds
elementwise (other.low <= self.low and other.high >= self.high).
Infinite bounds are handled correctly via direct comparison since
±inf compares as expected against finite values and itself.
device is ignored.
data_to
¶
data_to(data: BArrayType, backend: Optional[ComputeBackend] = None, device: Optional[Union[BDeviceType, Any]] = None) -> Union[BArrayType, Any]
Convert data to another backend.
DynamicBoxSpace
¶
DynamicBoxSpace(backend: ComputeBackend[BArrayType, BDeviceType, BDtypeType, BRNGType], low: Union[int, float, BArrayType], high: Union[int, float, BArrayType], shape_low: Sequence[int], shape_high: Sequence[int], dtype: BDtypeType, device: Optional[BDeviceType] = None, fill_value: Union[int, float] = 0)
Bases: Space[BArrayType, BDeviceType, BDtypeType, BRNGType]
shape
property
¶
shape: tuple[int, ...] | None
Return the shape of the space as an immutable property.
low
property
¶
low: BArrayType
Broadcasted lower bounds at the space's broadcast shape.
For a dynamic box there is no single fixed shape — only a range
[shape_low, shape_high] per axis. The stored _low/_high
arrays are broadcastable to self._broadcast_shape (shape_low
with size 1 on every dynamic axis, i.e. axes where
shape_low != shape_high). This property returns the bounds
broadcast to that _broadcast_shape, mirroring BoxSpace.low
(which broadcasts to self.shape). Comparisons against data of any
in-range shape broadcast correctly because dynamic axes carry size 1
here. Use get_low(shape) / get_high(shape) to materialize the
bounds at a specific concrete shape.
high
property
¶
high: BArrayType
Broadcasted upper bounds at the space's broadcast shape.
See low for the rationale behind the chosen shape.
is_subspace
¶
is_subspace(other: Space) -> bool
Return whether this space is a STRICT subspace of other (self ⊂ other).
Defined uniformly for all spaces as::
self.is_subspace(other) ⟺ self.is_subspaceeq(other) and not other.is_subspaceeq(self)
I.e. self ⊆ other holds but other ⊆ self does not, so self
is a PROPER (strict) subspace of other. This is the ⊂ relation
versus the non-strict ⊆ provided by :meth:is_subspaceeq.
This definition is used instead of relying on __eq__ because some
space classes only have identity __eq__; defining strict
containment via the symmetric non-strict check works uniformly for all
classes regardless of their __eq__ implementation.
For structurally-distinct-but-mutually-containing spaces (which should
not occur under the strict dtype/shape policies enforced by the
per-class is_subspaceeq implementations) this degrades gracefully
to False: if both self.is_subspaceeq(other) and
other.is_subspaceeq(self) hold, the two spaces are considered
equivalent and neither is a STRICT subspace of the other.
If either side's is_subspaceeq is not implemented (the base
:meth:is_subspaceeq raises NotImplementedError), the exception
propagates to the caller — it is NOT swallowed into False so that
callers can tell that the comparison is unsupported.
Note: controller-required-space checks should typically use
:meth:is_subspaceeq (a controller's required space may exactly equal
the env space, in which case the strict is_subspace would return
False).
abbr_device
staticmethod
¶
abbr_device(spaces: Iterable[Space[Any, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT]]) -> Optional[_SpaceBDeviceT]
Return the shared device across spaces, or None if mixed/empty.
pad_array_on_axis
staticmethod
¶
pad_array_on_axis(backend: ComputeBackend[BArrayType, BDeviceType, BDtypeType, BRNGType], data: BArrayType, axis: int, target_size: int, fill_value: Union[int, float] = 0) -> BArrayType
get_array_axis_length
staticmethod
¶
get_array_axis_length(backend: ComputeBackend[BArrayType, BDeviceType, BDtypeType, BRNGType], data: BArrayType, axis: int, fill_value: Union[int, float] = 0) -> int
unpad_array_on_axis
staticmethod
¶
unpad_array_on_axis(backend: ComputeBackend[BArrayType, BDeviceType, BDtypeType, BRNGType], data: BArrayType, axis: int, fill_value: Union[int, float] = 0) -> BArrayType
to
¶
to(backend: Optional[ComputeBackend] = None, device: Optional[Union[BDeviceType, Any]] = None) -> Union[DynamicBoxSpace[BArrayType, BDeviceType, BDtypeType, BRNGType], DynamicBoxSpace]
sample
¶
sample(rng: BRNGType) -> Tuple[BRNGType, BArrayType]
Generates a single random sample inside the Box.
In creating a sample of the box, each coordinate is sampled (independently) from a distribution that is chosen according to the form of the interval:
- :math:
[a, b]: uniform distribution - :math:
[a, \infty): shifted exponential distribution - :math:
(-\infty, b]: shifted negative exponential distribution - :math:
(-\infty, \infty): normal distribution
Returns:
| Type | Description |
|---|---|
Tuple[BRNGType, BArrayType]
|
A sampled value from the Box |
pad_data
¶
pad_data(data: BArrayType, start_axis: Optional[int] = None, end_axis: Optional[int] = None) -> BArrayType
Pad the data to the maximum shape of this space.
unpad_data
¶
unpad_data(data: BArrayType, start_axis: Optional[int] = None, end_axis: Optional[int] = None) -> BArrayType
Unpad the data to the minimum shape of this space.
shape_contains
¶
shape_contains(shape: Sequence[int]) -> bool
Check if the shape is within the bounds of this space.
clip
¶
clip(x: BArrayType) -> BArrayType
Clip the values of x to be within the bounds of this space.
get_repr
¶
get_repr(abbreviate: bool = False, include_backend: bool = True, include_device: bool = True, include_dtype: bool = True) -> str
is_subspaceeq
¶
is_subspaceeq(other: Any) -> bool
Return whether this dynamic box is a non-strict subspace of other (⊆).
True iff other is a DynamicBoxSpace on the same backend with
equal dtype, self's shape range is contained within other's
(other.shape_low <= self.shape_low and
self.shape_high <= other.shape_high per dimension, inf-aware via
plain integer comparison), and the value bounds of self are
contained within other's. The value-bounds check is performed by
broadcasting both spaces' bounds to a common shape (the elementwise
maximum of the two shape_high vectors along each axis, restricted
to axes where the two ranges overlap) via get_low/get_high.
.. note::
This class exposes get_low/get_high but no low/high
properties, even though __eq__ and contains reference
self.low/self.high. This implementation deliberately avoids
self.low/self.high and uses get_low/get_high
instead; the pre-existing bug in __eq__/contains is left
untouched per scope.
data_to
¶
data_to(data: BArrayType, backend: Optional[ComputeBackend] = None, device: Optional[Union[BDeviceType, Any]] = None) -> Union[BArrayType, Any]
Convert data to another backend.
DictSpace
¶
DictSpace(backend: ComputeBackend[Any, BDeviceType, BDtypeType, BRNGType], spaces: Optional[Union[Dict[str, Space[Any, BDeviceType, BDtypeType, BRNGType]], Sequence[Tuple[str, Space[Any, BDeviceType, BDtypeType, BRNGType]]]]] = None, device: Optional[BDeviceType] = None)
Bases: Space[Dict[str, Any], BDeviceType, BDtypeType, BRNGType]
Cartesian product of named subspaces represented as a mapping.
Create a dictionary-valued space from named child spaces.
shape
property
¶
shape: tuple[int, ...] | None
Return the shape of the space as an immutable property.
is_subspace
¶
is_subspace(other: Space) -> bool
Return whether this space is a STRICT subspace of other (self ⊂ other).
Defined uniformly for all spaces as::
self.is_subspace(other) ⟺ self.is_subspaceeq(other) and not other.is_subspaceeq(self)
I.e. self ⊆ other holds but other ⊆ self does not, so self
is a PROPER (strict) subspace of other. This is the ⊂ relation
versus the non-strict ⊆ provided by :meth:is_subspaceeq.
This definition is used instead of relying on __eq__ because some
space classes only have identity __eq__; defining strict
containment via the symmetric non-strict check works uniformly for all
classes regardless of their __eq__ implementation.
For structurally-distinct-but-mutually-containing spaces (which should
not occur under the strict dtype/shape policies enforced by the
per-class is_subspaceeq implementations) this degrades gracefully
to False: if both self.is_subspaceeq(other) and
other.is_subspaceeq(self) hold, the two spaces are considered
equivalent and neither is a STRICT subspace of the other.
If either side's is_subspaceeq is not implemented (the base
:meth:is_subspaceeq raises NotImplementedError), the exception
propagates to the caller — it is NOT swallowed into False so that
callers can tell that the comparison is unsupported.
Note: controller-required-space checks should typically use
:meth:is_subspaceeq (a controller's required space may exactly equal
the env space, in which case the strict is_subspace would return
False).
abbr_device
staticmethod
¶
abbr_device(spaces: Iterable[Space[Any, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT]]) -> Optional[_SpaceBDeviceT]
Return the shared device across spaces, or None if mixed/empty.
to
¶
to(backend: Optional[ComputeBackend] = None, device: Optional[Union[BDeviceType, Any]] = None) -> Union[DictSpace[BDeviceType, BDtypeType, BRNGType], DictSpace]
is_subspaceeq
¶
is_subspaceeq(other: Any) -> bool
Return whether this dict space is a non-strict subspace of other (⊆).
True iff other is a DictSpace on the same backend, every key of
self is present in other (self.keys() ⊆ other.keys()), and
for every shared key self.spaces[k].is_subspaceeq(other.spaces[k])
holds recursively. Unlike contains, other is permitted to
expose EXTRA keys beyond those of self — this is the controller
required-observation-space use case where the environment may provide
additional observation entries. device is ignored.
get_repr
¶
get_repr(abbreviate: bool = False, include_backend: bool = True, include_device: bool = True, include_dtype: bool = True) -> str
GraphSpace
¶
GraphSpace(backend: ComputeBackend[BArrayType, BDeviceType, BDtypeType, BRNGType], node_feature_space: Optional[BoxSpace[BArrayType, BDeviceType, BDtypeType, BRNGType]], edge_feature_space: Optional[BoxSpace[BArrayType, BDeviceType, BDtypeType, BRNGType]] = None, is_edge: bool = False, min_nodes: int = 1, max_nodes: Optional[int] = None, min_edges: int = 1, max_edges: Optional[int] = None, batch_shape: Sequence[int] = (), device: Optional[BDeviceType] = None)
Bases: Space[GraphInstance[BArrayType], BDeviceType, BDtypeType, BRNGType], Generic[BArrayType, BDeviceType, BDtypeType, BRNGType]
shape
property
¶
shape: tuple[int, ...] | None
Return the shape of the space as an immutable property.
node_feature_space
instance-attribute
¶
node_feature_space = node_feature_space if (device is None or node_feature_space is None) else node_feature_space.to(device=device)
edge_feature_space
instance-attribute
¶
edge_feature_space = edge_feature_space if (device is None or edge_feature_space is None) else edge_feature_space.to(device=device)
is_subspace
¶
is_subspace(other: Space) -> bool
Return whether this space is a STRICT subspace of other (self ⊂ other).
Defined uniformly for all spaces as::
self.is_subspace(other) ⟺ self.is_subspaceeq(other) and not other.is_subspaceeq(self)
I.e. self ⊆ other holds but other ⊆ self does not, so self
is a PROPER (strict) subspace of other. This is the ⊂ relation
versus the non-strict ⊆ provided by :meth:is_subspaceeq.
This definition is used instead of relying on __eq__ because some
space classes only have identity __eq__; defining strict
containment via the symmetric non-strict check works uniformly for all
classes regardless of their __eq__ implementation.
For structurally-distinct-but-mutually-containing spaces (which should
not occur under the strict dtype/shape policies enforced by the
per-class is_subspaceeq implementations) this degrades gracefully
to False: if both self.is_subspaceeq(other) and
other.is_subspaceeq(self) hold, the two spaces are considered
equivalent and neither is a STRICT subspace of the other.
If either side's is_subspaceeq is not implemented (the base
:meth:is_subspaceeq raises NotImplementedError), the exception
propagates to the caller — it is NOT swallowed into False so that
callers can tell that the comparison is unsupported.
Note: controller-required-space checks should typically use
:meth:is_subspaceeq (a controller's required space may exactly equal
the env space, in which case the strict is_subspace would return
False).
abbr_device
staticmethod
¶
abbr_device(spaces: Iterable[Space[Any, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT]]) -> Optional[_SpaceBDeviceT]
Return the shared device across spaces, or None if mixed/empty.
to
¶
to(backend: Optional[ComputeBackend] = None, device: Optional[Union[BDeviceType, Any]] = None) -> Union[GraphSpace[BArrayType, BDeviceType, BDtypeType, BRNGType], GraphSpace]
contains
¶
contains(x: GraphInstance[BArrayType]) -> bool
Return boolean specifying if x is a valid member of this space.
get_repr
¶
get_repr(abbreviate=False, include_backend=True, include_device=True, include_dtype=True)
is_subspaceeq
¶
is_subspaceeq(other: Any) -> bool
Return whether this graph space is a non-strict subspace of other (⊆).
True iff other is a GraphSpace on the same backend, the node
and edge feature spaces are subspaces recursively, and self's
node/edge count ranges are contained within other's:
other.min_nodes <= self.min_nodesandself.max_nodes <= other.max_nodes(treatingNoneas +∞);- likewise for edges, with the additional requirement that
self.is_edgeandother.is_edgeagree (an edge-less space cannot be a subspace of an edge-bearing one and vice versa).
device is ignored.
GraphInstance
dataclass
¶
GraphInstance(n_nodes: BArrayType, n_edges: Optional[BArrayType] = None, nodes_features: Optional[BArrayType] = None, edges_features: Optional[BArrayType] = None, edges: Optional[BArrayType] = None)
Bases: Generic[BArrayType]
n_edges
class-attribute
instance-attribute
¶
n_edges: Optional[BArrayType] = None
Number of edges in the graph, shape (*batch_shape) or None if no edges are present.
nodes_features
class-attribute
instance-attribute
¶
nodes_features: Optional[BArrayType] = None
Node features, shape (batch_shape, max(n_nodes), node_feature_space.shape) if node_feature_space is not None, otherwise None.
edges_features
class-attribute
instance-attribute
¶
edges_features: Optional[BArrayType] = None
Edge features, shape (batch_shape, max(n_edges), edge_feature_space.shape) if edge_feature_space is not None, otherwise None.
edges
class-attribute
instance-attribute
¶
edges: Optional[BArrayType] = None
Edges in the graph, shape (*batch_shape, max(n_edges), 2) where each edge is represented by a pair of node indices, or None if no edges are present.
TextSpace
¶
TextSpace(backend: ComputeBackend[Any, BDeviceType, BDtypeType, BRNGType], max_length: int, *, min_length: int = 0, charset: Optional[FrozenSet[str] | str] = None, device: Optional[BDeviceType] = None)
Bases: Space[str, BDeviceType, BDtypeType, BRNGType]
shape
property
¶
shape: tuple[int, ...] | None
Return the shape of the space as an immutable property.
is_subspace
¶
is_subspace(other: Space) -> bool
Return whether this space is a STRICT subspace of other (self ⊂ other).
Defined uniformly for all spaces as::
self.is_subspace(other) ⟺ self.is_subspaceeq(other) and not other.is_subspaceeq(self)
I.e. self ⊆ other holds but other ⊆ self does not, so self
is a PROPER (strict) subspace of other. This is the ⊂ relation
versus the non-strict ⊆ provided by :meth:is_subspaceeq.
This definition is used instead of relying on __eq__ because some
space classes only have identity __eq__; defining strict
containment via the symmetric non-strict check works uniformly for all
classes regardless of their __eq__ implementation.
For structurally-distinct-but-mutually-containing spaces (which should
not occur under the strict dtype/shape policies enforced by the
per-class is_subspaceeq implementations) this degrades gracefully
to False: if both self.is_subspaceeq(other) and
other.is_subspaceeq(self) hold, the two spaces are considered
equivalent and neither is a STRICT subspace of the other.
If either side's is_subspaceeq is not implemented (the base
:meth:is_subspaceeq raises NotImplementedError), the exception
propagates to the caller — it is NOT swallowed into False so that
callers can tell that the comparison is unsupported.
Note: controller-required-space checks should typically use
:meth:is_subspaceeq (a controller's required space may exactly equal
the env space, in which case the strict is_subspace would return
False).
abbr_device
staticmethod
¶
abbr_device(spaces: Iterable[Space[Any, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT]]) -> Optional[_SpaceBDeviceT]
Return the shared device across spaces, or None if mixed/empty.
get_repr
¶
get_repr(abbreviate=False, include_backend=True, include_device=True, include_dtype=True)
is_subspaceeq
¶
is_subspaceeq(other: Any) -> bool
Return whether this text space is a non-strict subspace of other (⊆).
True iff other is a TextSpace on the same backend, self's
charset is a subset of other's charset (a None charset on
self is a subset of any charset; a None charset on other
only contains a None charset on self), self.min_length >=
other.min_length and self.max_length <= other.max_length.
device is ignored.
TupleSpace
¶
TupleSpace(backend: ComputeBackend[Any, BDeviceType, BDtypeType, BRNGType], spaces: Iterable[Space[Any, BDeviceType, BDtypeType, BRNGType]], device: Optional[BDeviceType] = None)
Bases: Space[Tuple[Any, ...], BDeviceType, BDtypeType, BRNGType]
shape
property
¶
shape: tuple[int, ...] | None
Return the shape of the space as an immutable property.
spaces
instance-attribute
¶
spaces: Tuple[Space[Any, BDeviceType, BDtypeType, BRNGType], ...] = tuple(new_spaces)
is_subspace
¶
is_subspace(other: Space) -> bool
Return whether this space is a STRICT subspace of other (self ⊂ other).
Defined uniformly for all spaces as::
self.is_subspace(other) ⟺ self.is_subspaceeq(other) and not other.is_subspaceeq(self)
I.e. self ⊆ other holds but other ⊆ self does not, so self
is a PROPER (strict) subspace of other. This is the ⊂ relation
versus the non-strict ⊆ provided by :meth:is_subspaceeq.
This definition is used instead of relying on __eq__ because some
space classes only have identity __eq__; defining strict
containment via the symmetric non-strict check works uniformly for all
classes regardless of their __eq__ implementation.
For structurally-distinct-but-mutually-containing spaces (which should
not occur under the strict dtype/shape policies enforced by the
per-class is_subspaceeq implementations) this degrades gracefully
to False: if both self.is_subspaceeq(other) and
other.is_subspaceeq(self) hold, the two spaces are considered
equivalent and neither is a STRICT subspace of the other.
If either side's is_subspaceeq is not implemented (the base
:meth:is_subspaceeq raises NotImplementedError), the exception
propagates to the caller — it is NOT swallowed into False so that
callers can tell that the comparison is unsupported.
Note: controller-required-space checks should typically use
:meth:is_subspaceeq (a controller's required space may exactly equal
the env space, in which case the strict is_subspace would return
False).
abbr_device
staticmethod
¶
abbr_device(spaces: Iterable[Space[Any, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT]]) -> Optional[_SpaceBDeviceT]
Return the shared device across spaces, or None if mixed/empty.
get_repr
¶
get_repr(abbreviate=False, include_backend=True, include_device=True, include_dtype=True)
is_subspaceeq
¶
is_subspaceeq(other: Any) -> bool
Return whether this tuple space is a non-strict subspace of other (⊆).
True iff other is a TupleSpace on the same backend, the two
have the same arity, and for every index i the child
self.spaces[i].is_subspaceeq(other.spaces[i]) holds recursively.
device is ignored.
UnionSpace
¶
UnionSpace(backend: ComputeBackend[Any, BDeviceType, BDtypeType, BRNGType], spaces: Iterable[Space[Any, BDeviceType, BDtypeType, BRNGType]], device: Optional[BDeviceType] = None)
Bases: Space[Tuple[int, Any], BDeviceType, BDtypeType, BRNGType]
shape
property
¶
shape: tuple[int, ...] | None
Return the shape of the space as an immutable property.
spaces
instance-attribute
¶
spaces = tuple(spaces if device is None else [(space.to(device=device)) for space in spaces])
is_subspace
¶
is_subspace(other: Space) -> bool
Return whether this space is a STRICT subspace of other (self ⊂ other).
Defined uniformly for all spaces as::
self.is_subspace(other) ⟺ self.is_subspaceeq(other) and not other.is_subspaceeq(self)
I.e. self ⊆ other holds but other ⊆ self does not, so self
is a PROPER (strict) subspace of other. This is the ⊂ relation
versus the non-strict ⊆ provided by :meth:is_subspaceeq.
This definition is used instead of relying on __eq__ because some
space classes only have identity __eq__; defining strict
containment via the symmetric non-strict check works uniformly for all
classes regardless of their __eq__ implementation.
For structurally-distinct-but-mutually-containing spaces (which should
not occur under the strict dtype/shape policies enforced by the
per-class is_subspaceeq implementations) this degrades gracefully
to False: if both self.is_subspaceeq(other) and
other.is_subspaceeq(self) hold, the two spaces are considered
equivalent and neither is a STRICT subspace of the other.
If either side's is_subspaceeq is not implemented (the base
:meth:is_subspaceeq raises NotImplementedError), the exception
propagates to the caller — it is NOT swallowed into False so that
callers can tell that the comparison is unsupported.
Note: controller-required-space checks should typically use
:meth:is_subspaceeq (a controller's required space may exactly equal
the env space, in which case the strict is_subspace would return
False).
abbr_device
staticmethod
¶
abbr_device(spaces: Iterable[Space[Any, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT]]) -> Optional[_SpaceBDeviceT]
Return the shared device across spaces, or None if mixed/empty.
contains
¶
contains(x: Tuple[int, Any]) -> bool
Return boolean specifying if x is a valid member of this space.
get_repr
¶
get_repr(abbreviate: bool = False, include_backend=True, include_device=True, include_dtype=True)
is_subspaceeq
¶
is_subspaceeq(other: Any) -> bool
Return whether this union space is a non-strict subspace of other (⊆).
Kept simple: True iff other is a UnionSpace on the same backend
with the same number of alternatives and, for every index i,
self.spaces[i].is_subspaceeq(other.spaces[i]) holds (pairwise,
same-index recursion). This is a conservative structural check — it
does not attempt to reason about alternative reordering or set-union
semantics. device is ignored.
BatchedSpace
¶
BatchedSpace(single_space: Space[SpaceDataT, BDeviceType, BDtypeType, BRNGType], batch_shape: Sequence[int])
Bases: Space[ndarray, BDeviceType, BDtypeType, BRNGType]
This space represents a batch of
shape
property
¶
shape: tuple[int, ...] | None
Return the shape of the space as an immutable property.
is_subspace
¶
is_subspace(other: Space) -> bool
Return whether this space is a STRICT subspace of other (self ⊂ other).
Defined uniformly for all spaces as::
self.is_subspace(other) ⟺ self.is_subspaceeq(other) and not other.is_subspaceeq(self)
I.e. self ⊆ other holds but other ⊆ self does not, so self
is a PROPER (strict) subspace of other. This is the ⊂ relation
versus the non-strict ⊆ provided by :meth:is_subspaceeq.
This definition is used instead of relying on __eq__ because some
space classes only have identity __eq__; defining strict
containment via the symmetric non-strict check works uniformly for all
classes regardless of their __eq__ implementation.
For structurally-distinct-but-mutually-containing spaces (which should
not occur under the strict dtype/shape policies enforced by the
per-class is_subspaceeq implementations) this degrades gracefully
to False: if both self.is_subspaceeq(other) and
other.is_subspaceeq(self) hold, the two spaces are considered
equivalent and neither is a STRICT subspace of the other.
If either side's is_subspaceeq is not implemented (the base
:meth:is_subspaceeq raises NotImplementedError), the exception
propagates to the caller — it is NOT swallowed into False so that
callers can tell that the comparison is unsupported.
Note: controller-required-space checks should typically use
:meth:is_subspaceeq (a controller's required space may exactly equal
the env space, in which case the strict is_subspace would return
False).
abbr_device
staticmethod
¶
abbr_device(spaces: Iterable[Space[Any, _SpaceBDeviceT, _SpaceBDTypeT, _SpaceBDRNGT]]) -> Optional[_SpaceBDeviceT]
Return the shared device across spaces, or None if mixed/empty.
get_repr
¶
get_repr(abbreviate=False, include_backend=True, include_device=True, include_dtype=True)
is_subspaceeq
¶
is_subspaceeq(other: Any) -> bool
Return whether this batched space is a subspace of other.
True iff other is a BatchedSpace on the same backend with equal
batch_shape and self.single_space.is_subspaceeq(other.single_space)
holds recursively (non-strict ⊆). device is ignored.