Skip to content

Commit 51b7c72

Browse files
authored
Enhance docstrings for topological sort methods (#1413)
1 parent 0e338fd commit 51b7c72

File tree

1 file changed

+78
-48
lines changed

1 file changed

+78
-48
lines changed

src/dag_algo/mod.rs

Lines changed: 78 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -343,41 +343,47 @@ pub fn layers(
343343
Ok(pylist.into())
344344
}
345345
}
346-
/// Get the lexicographical topological sorted nodes from the provided DAG
347-
///
348-
/// This function returns a list of nodes data in a graph lexicographically
349-
/// topologically sorted using the provided key function. A topological sort
350-
/// is a linear ordering of vertices such that for every directed edge from
351-
/// node :math:`u` to node :math:`v`, :math:`u` comes before :math:`v`
352-
/// in the ordering. If ``reverse`` is set to ``False``, the edges are treated
353-
/// as if they pointed in the opposite direction.
354-
///
355-
/// This function differs from :func:`~rustworkx.topological_sort` because
356-
/// when there are ties between nodes in the sort order this function will
357-
/// use the string returned by the ``key`` argument to determine the output
358-
/// order used. The ``reverse`` argument does not affect the ordering of keys
359-
/// from this function, only the edges of the graph.
360-
///
361-
/// :param PyDiGraph dag: The DAG to get the topological sorted nodes from
362-
/// :param callable key: key is a python function or other callable that
363-
/// gets passed a single argument the node data from the graph and is
364-
/// expected to return a string which will be used for resolving ties
365-
/// in the sorting order.
366-
/// :param bool reverse: If ``False`` (the default), perform a regular
367-
/// topological ordering. If ``True``, return the lexicographical
368-
/// topological order that would have been found if all the edges in the
369-
/// graph were reversed. This does not affect the comparisons from the
370-
/// ``key``.
371-
/// :param Iterable[int] initial: If given, the initial node indices to start the topological
372-
/// ordering from. If not given, the topological ordering will certainly contain every node in
373-
/// the graph. If given, only the ``initial`` nodes and nodes that are dominated by the
374-
/// ``initial`` set will be in the ordering. Notably, any node that has a natural in degree of
375-
/// zero will not be in the output ordering if ``initial`` is given and the zero-in-degree node
376-
/// is not in it. It is a :exc:`ValueError` to give an `initial` set where the nodes have even
377-
/// a partial topological order between themselves.
378-
///
379-
/// :returns: A list of node's data lexicographically topologically sorted.
380-
/// :rtype: list
346+
347+
/// Get the lexicographical topological sorted nodes from the provided directed
348+
/// graph.
349+
///
350+
/// This function returns a list of node data from the graph, sorted in
351+
/// lexicographical order based on the provided key function. A topological sort
352+
/// is a linear ordering of vertices such that for every directed edge from node
353+
/// :math:`u` to node :math:`v`, :math:`u` appears before :math:`v` in the
354+
/// ordering. If `reverse` is set to `False`, the edges are treated as if they
355+
/// point in the opposite direction.
356+
///
357+
/// Unlike :func:`~rustworkx.topological_sort`, this function resolves ties
358+
/// between nodes using the string returned by the `key` argument. The `reverse`
359+
/// argument only affects the direction of the edges, not the ordering of keys.
360+
///
361+
/// >>> G = rx.PyDiGraph()
362+
/// >>> a, b, c, d, e, f, g = G.add_nodes_from(["A", "B", "C", "D", "E", "F", "G"])
363+
/// >>> G.add_edges_from_no_data([(a, g), (b, g), (c, g), (d, g), (e, g), (f, g)])
364+
/// >>> rx.topological_sort(G)
365+
/// NodeIndices[5, 4, 3, 2, 1, 0, 6] # First 6 items in any order
366+
/// >>> rx.lexicographical_topological_sort(G, key=str)
367+
/// ['A', 'B', 'C', 'D', 'E', 'F', 'G'] # First 6 items in alphabetical order
368+
///
369+
/// For a standard topological sort without lexicographical ordering, see
370+
/// :func:`~rustworkx.topological_sort`.
371+
///
372+
/// :param PyDiGraph dag: The directed graph to sort.
373+
/// :param callable key: A callable that takes a single argument (node data) and
374+
/// returns a string used to resolve ties in the sorting order.
375+
/// :param bool reverse: If `False` (default), perform a regular topological
376+
/// ordering. If `True`, return the lexicographical order as if all edges
377+
/// were reversed. This does not affect the comparisons from the `key`.
378+
/// :param Iterable[int] initial: By default, the topological ordering will
379+
/// include all nodes in the graph. If ``initial`` node indices are
380+
/// provided, the ordering will only include those nodes and any nodes that
381+
/// are dominated by them. Providing an initial set where the nodes have
382+
/// even a partial topological order among themselves will raise a
383+
/// :exc:`ValueError`.
384+
///
385+
/// :returns: A list of node data, lexicographically topologically sorted.
386+
/// :rtype: list[S]
381387
#[pyfunction]
382388
#[pyo3(signature = (dag, /, key, *, reverse=false, initial=None))]
383389
pub fn lexicographical_topological_sort(
@@ -413,19 +419,28 @@ pub fn lexicographical_topological_sort(
413419
.into())
414420
}
415421

416-
/// Return the topological generations of a DAG
422+
/// Return the topological generations of a directed graph.
417423
///
418-
/// A topological generation is node collection in which ancestors of a node in each
419-
/// generation are guaranteed to be in a previous generation, and any descendants of
420-
/// a node are guaranteed to be in a following generation. Nodes are guaranteed to
421-
/// be in the earliest possible generation that they can belong to.
424+
/// A topological generation is a collection of nodes where all ancestors of a
425+
/// node are guaranteed to be in a previous generation, and all descendants of a
426+
/// node are guaranteed to be in a subsequent generation. Nodes are placed in
427+
/// the earliest possible generation they can belong to.
422428
///
423-
/// :param PyDiGraph graph: The DAG to get the topological generations from
429+
/// >>> G = rx.PyDiGraph()
430+
/// >>> G.add_nodes_from([0, 1, 2, 3, 4])
431+
/// >>> G.add_edges_from_no_data([(0, 1), (0, 2), (1, 3), (2, 3), (3, 4)])
432+
/// >>> rx.topological_generations(G)
433+
/// [NodeIndices[0], NodeIndices[1, 2], NodeIndices[3], NodeIndices[4]]
424434
///
425-
/// :returns: A list of topological generations.
426-
/// :rtype: list
435+
/// For a topologically sorted node list without generations, see :func:`~topological_sort`.
436+
///
437+
/// For more advanced control over the nodes iteration, see :class:`~rustworkx.TopologicalSorter`.
427438
///
428-
/// :raises DAGHasCycle: if a cycle is encountered while sorting the graph
439+
/// :param PyDiGraph dag: The directed graph to get the topological generations from.
440+
/// :returns: A list of topological generations, where each generation is
441+
/// represented as a list of node indices.
442+
/// :rtype: list[NodeIndices]
443+
/// :raises DAGHasCycle: if a cycle is encountered while processing the graph.o
429444
#[pyfunction]
430445
#[pyo3(text_signature = "(dag, /)")]
431446
pub fn topological_generations(dag: &digraph::PyDiGraph) -> PyResult<Vec<NodeIndices>> {
@@ -468,14 +483,29 @@ pub fn topological_generations(dag: &digraph::PyDiGraph) -> PyResult<Vec<NodeInd
468483
Ok(generations)
469484
}
470485

471-
/// Return the topological sort of node indices from the provided graph
486+
/// Return the topological sort of node indices from the provided directed
487+
/// graph.
472488
///
473-
/// :param PyDiGraph graph: The DAG to get the topological sort on
489+
/// Computes a topological ordering of the nodes in the given directed graph,
490+
/// ensuring that for every directed edge from node :math:`u` to node :math:`v`,
491+
/// node :math:`u` appears before node :math:`v` in the resulting sequence. This
492+
/// is particularly useful in scenarios such as task scheduling and dependency
493+
/// resolution, where certain tasks must be completed before others.
474494
///
495+
/// >>> G = rx.PyDiGraph()
496+
/// >>> G.add_nodes_from(["A", "B", "C", "D", "E", "F", "G"])
497+
/// >>> G.add_edges_from_no_data([(0, 1),(1, 2), (2, 3), (3, 4), (5, 2), (6, 3)])
498+
/// >>> rx.topological_sort(G)
499+
/// NodeIndices[6, 5, 0, 1, 2, 3, 4]
500+
///
501+
/// For more advanced control over the nodes iteration, see :class:`~rustworkx.TopologicalSorter`.
502+
///
503+
/// For custom sorting algorithm, see :func:`~lexicographical_topological_sort`.
504+
///
505+
/// :param PyDiGraph graph: The directed graph to get the topological sort on.
475506
/// :returns: A list of node indices topologically sorted.
476507
/// :rtype: NodeIndices
477-
///
478-
/// :raises DAGHasCycle: if a cycle is encountered while sorting the graph
508+
/// :raises DAGHasCycle: if a cycle is encountered while sorting the graph.
479509
#[pyfunction]
480510
#[pyo3(text_signature = "(graph, /)")]
481511
pub fn topological_sort(graph: &digraph::PyDiGraph) -> PyResult<NodeIndices> {

0 commit comments

Comments
 (0)