toponetx.Path#

class toponetx.Path(elements: Sequence[Hashable] | Hashable, construct_boundaries: bool = False, reserve_sequence_order: bool = False, allowed_paths: Iterable[tuple[Hashable]] | None = None, **kwargs)[source]#

Bases: Atom[tuple[Hashable]]

Path class.

A class representing an elementary p-path in a path complex, which is the building block for a path complex. By the definition established in the original paper [2], an elementary p-path on a non-empty set of vertices V is any sequence of vertices with length p + 1.

Unlike the original paper [2] where elementary p-paths span the regular space of boundary-invariant paths, the elementary p-paths represented by this class span the space of simple paths with length p as proposed in [1].

Parameters:
elementsSequence[Hashable]

The nodes in the elementary p-path.

construct_boundariesbool, default=False

If True, construct the entire boundary of the elementary p-path.

reserve_sequence_orderbool, default=False

If True, reserve the order of the sub-sequence of nodes in the elementary p-path. Else, the sub-sequence of nodes in the elementary p-path will be reversed if the first index is larger than the last index.

allowed_pathsIterable[tuple[Hashable]], optional

A list of allowed boundaries of an elementary p-path. If None, all possible boundaries are constructed (similarly to simplex).

**kwargskeyword arguments, optional

Additional attributes to be associated with the elementary p-path.

Attributes:
boundary

Return the boundary of this path.

Methods

clone()

Return a shallow copy of the elementary p-path.

construct_path_boundaries(elements[, ...])

Return list of elementary p-path objects representing the boundaries.

update(attributes)

Update the attributes of the atom.

Notes

  • An elementary p-path is defined as an ordered sequence of nodes (n1, …, np) if we reserve the sequence order. Thus, for this case, (n1, …, np) is different from (np, …, n1). If we do not reserve the sequence order, then (n1, …, np) is the same as (np, …, n1). For this case, the first index must be smaller than the last index so that we can discard the other duplicate elementary p-path. As elementary p-paths may contain characters and numbers at the same time, we leverage lexicographical order to compare two indices.

  • Similarly to simplex, in order to find the boundary of an elementary p-path, we remove one node at a time from the elementary p-path. However, unlike simplex where order does not matter, the process of omitting nodes from an elementary p-path may result some non-existing paths. For instance, if we have an elementary p-path (1, 2, 3) and there is no path (1, 3), then applying boundary operation on the elementary p-path results in [(2,3), (1,3), (1,2)]. In order to avoid this, we can provide a list of allowed boundaries. If the boundary of an elementary p-path is not in the list of allowed boundaries, then it will not be included in the boundary of the elementary p-path.

  • When an elementary p-path is created and allowed paths are not specified, its boundary is automatically created by iteratively removing one node at a time from the elementary p-path, which is identical to a simplex.

References

[1]

Truong and Chin. Generalizing Topological Graph Neural Networks with Paths. https://arxiv.org/abs/2308.06838.pdf

[2] (1,2)

Grigor’yan, Lin, Muranov, and Yau. Homologies of path complexes and digraphs. https://arxiv.org/pdf/1207.2834.pdf

Examples

>>> path1 = tnx.Path((1, 2, 3))
>>> list(path1.boundary)
[]
>>> path2 = tnx.Path((1, 2, 3), construct_boundaries=True)
>>> list(path2.boundary)
[(2, 3), (1, 3), (1, 2)]
>>> path3 = tnx.Path(
...     (1, 2, 3), construct_boundaries=True, allowed_paths=[(1, 2), (2, 3)]
... )
>>> list(path3.boundary)
[(2, 3), (1, 2)]
>>> path4 = tnx.Path(
...     (1, 2, 3), construct_boundaries=True, allowed_paths=[(1, 3), (2, 3)]
... )
>>> list(path4.boundary)
[(2, 3), (1, 3)]
__init__(elements: Sequence[Hashable] | Hashable, construct_boundaries: bool = False, reserve_sequence_order: bool = False, allowed_paths: Iterable[tuple[Hashable]] | None = None, **kwargs) None[source]#

Methods

__init__(elements[, construct_boundaries, ...])

clone()

Return a shallow copy of the elementary p-path.

construct_path_boundaries(elements[, ...])

Return list of elementary p-path objects representing the boundaries.

update(attributes)

Update the attributes of the atom.

Attributes

boundary

Return the boundary of this path.

elements

name

property boundary: list[tuple[Hashable, ...]]#

Return the boundary of this path.

The boundary of this path are all elementary (p-1)-path objects representing the elementary (p-1)-path on the boundary of the target elementary p-path.

Returns:
list[tuple[Hashable]]

List of elementary p-path objects representing the boundary (p-1)-paths.

clone() Self[source]#

Return a shallow copy of the elementary p-path.

Returns:
Path

A shallow copy of the elementary p-path.

static construct_path_boundaries(elements: Sequence[Hashable], reserve_sequence_order: bool = False, allowed_paths: Iterable[tuple[Hashable]] | None = None) list[tuple[Hashable, ...]][source]#

Return list of elementary p-path objects representing the boundaries.

Parameters:
elementsSequence[Hashable]

The nodes in the elementary p-path.

reserve_sequence_orderbool, default=False

If True, reserve the order of the sub-sequence of nodes in the elementary p-path. Else, the sub-sequence of nodes in the elementary p-path will be reversed if the first index is larger than the last index.

allowed_pathsIterable[tuple[Hashable]], optional

A list of allowed boundaries. If None, all possible boundaries are constructed (similarly to simplex).

Returns:
list[tuple[Hashable]]

List of elementary p-path objects representing the boundaries.

Notes

  • In order to construct a set of boundary (p-1)-paths of an elementary p-path (n1, …, np), we iteratively omit one node at a time from the elementary p-path. The resulted boundary paths are elementary (p-1)-paths in the form of (n1, …, ni-1, ni+1, …, np), where i is the index of the omitted node. However, some of the elementary (p-1)-paths may be non-existing (or non-allowed in our context), so we discard them from the boundary set.

Examples

>>> tnx.Path.construct_path_boundaries((1, 2, 3), reserve_sequence_order=False)
[(2, 3), (1, 3), (1, 2)]
>>> tnx.Path.construct_path_boundaries(
...     (1, 2, 3), reserve_sequence_order=False, allowed_paths=[(1, 2), (2, 3)]
... )
[(2, 3), (1, 2)]
update(attributes: dict) None#

Update the attributes of the atom.

Parameters:
attributesdict

The attributes to be updated.