Skip to content

unienv_interface.space.spaces.graph

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_nodes instance-attribute

n_nodes: BArrayType

Number of nodes in the graph, shape (*batch_shape)

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.

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]

batch_shape instance-attribute

batch_shape = tuple((int(dim)) for dim in batch_shape)

is_edge instance-attribute

is_edge = is_edge

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)

min_nodes instance-attribute

min_nodes = min_nodes

max_nodes instance-attribute

max_nodes = max_nodes

min_edges instance-attribute

min_edges = min_edges

max_edges instance-attribute

max_edges = max_edges

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.

to

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

sample

sample(rng: BRNGType) -> Tuple[BRNGType, GraphInstance]

create_empty

create_empty() -> GraphInstance[BArrayType]

is_bounded

is_bounded(manner='both')

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_nodes and self.max_nodes <= other.max_nodes (treating None as +∞);
  • likewise for edges, with the additional requirement that self.is_edge and other.is_edge agree (an edge-less space cannot be a subspace of an edge-bearing one and vice versa).

device is ignored.

data_to

data_to(data, backend=None, device=None)

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.