Skip to content

unienv_interface.space.spaces.dynamic_box

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]

fill_value instance-attribute

fill_value = fill_value

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.

shape_low property

shape_low: Tuple[int, ...]

Return the lower shape of the BoxSpace.

shape_high property

shape_high: Tuple[int, ...]

Return the upper shape of the BoxSpace.

backend instance-attribute

backend = backend

dtype instance-attribute

dtype = dtype

device property

device: Optional[_SpaceBDeviceT]

shape property

shape: tuple[int, ...] | None

Return the shape of the space as an immutable property.

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

get_low

get_low(shape: Sequence[int]) -> BArrayType

get_high

get_high(shape: Sequence[int]) -> BArrayType

to

to(backend: Optional[ComputeBackend] = None, device: Optional[Union[BDeviceType, Any]] = None) -> Union[DynamicBoxSpace[BArrayType, BDeviceType, BDtypeType, BRNGType], DynamicBoxSpace]

is_bounded

is_bounded(manner='both')

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.

create_empty

create_empty()

contains

contains(x: Any) -> bool

Return boolean specifying if x is a valid member 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.

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.