@@ -34,20 +34,31 @@ enum NodeState {
3434
3535/// Provides functionality to topologically sort a directed graph.
3636///
37+ /// A topological sorter is used to arrange the nodes of a directed acyclic
38+ /// graph in a linear order such that for every directed edge from node `u` to
39+ /// node `v`, node `u`` appears before node `v` in the sequence. This ordering
40+ /// is particularly useful for resolving dependencies in scenarios such as task
41+ /// scheduling, where certain tasks must be completed before others, and in
42+ /// build systems, where files or modules depend on one another. The topological
43+ /// sorting process ensures that all dependencies are satisfied, allowing for
44+ /// efficient execution and processing of tasks or data.
45+ ///
3746/// The steps required to perform the sorting of a given graph are as follows:
3847///
39- /// 1. Create an instance of the TopologicalSorter with an initial graph.
40- /// 2. While ` is_active()` is True, iterate over the nodes returned by ` get_ready()` and process them.
41- /// 3. Call ` done()` on each node as it finishes processing.
48+ /// 1. Create an instance of the ` TopologicalSorter` with an initial graph.
49+ /// 2. While :func:`~ is_active()` is True, iterate over the nodes returned by :func:`~ get_ready()` and process them.
50+ /// 3. Call :func:`~ done()` on each node as it finishes processing.
4251///
4352/// For example:
4453///
4554/// .. jupyter-execute::
4655///
4756/// import rustworkx as rx
4857///
49- /// graph = rx.generators.directed_path_graph(5)
50- /// sorter = rx.TopologicalSorter(graph)
58+ /// G = rx.PyDiGraph()
59+ /// G.add_nodes_from(["A", "B", "C", "D", "E", "F"])
60+ /// G.add_edges_from_no_data([(0, 2),(1, 2), (2, 3), (3, 4), (3, 5)])
61+ /// sorter = rx.TopologicalSorter(G)
5162/// while sorter.is_active():
5263/// nodes = sorter.get_ready()
5364/// print(nodes)
@@ -57,27 +68,25 @@ enum NodeState {
5768/// but it's not recommended doing it as it may result in a logical-error.
5869///
5970/// :param PyDiGraph graph: The directed graph to be used.
60- /// :param bool check_cycle: When this is set to ``True``, we search
71+ /// :param bool check_cycle: When this is set to ``True`` (the default) , we search
6172/// for cycles in the graph during initialization of topological sorter
6273/// and raise :class:`~rustworkx.DAGHasCycle` if any cycle is detected. If
6374/// it's set to ``False``, topological sorter will output as many nodes
64- /// as possible until cycles block more progress. By default is ``True``.
65- /// :param bool reverse: If ``False`` (the default), perform a regular topological ordering. If
66- /// ``True``, the ordering will be a reversed topological ordering; that is, a topological
67- /// order if all the edges had their directions flipped, such that the first nodes returned are
68- /// the ones that have only incoming edges in the DAG.
69- /// :param Iterable[int] initial: If given, the initial node indices to start the topological
70- /// ordering from. If not given, the topological ordering will certainly contain every node in
71- /// the graph. If given, only the ``initial`` nodes and nodes that are dominated by the
72- /// ``initial`` set will be in the ordering. Notably, the first return from :meth:`get_ready`
73- /// will be the same set of values as ``initial``, and any node that has a natural in
74- /// degree of zero will not be in the output ordering if ``initial`` is given and the
75- /// zero-in-degree node is not in it.
76- ///
77- /// It is a :exc:`ValueError` to give an `initial` set where the nodes have even a partial
78- /// topological order between themselves, though this might not appear until some call
79- /// to :meth:`done`.
80- /// :param bool check_args: If ``True`` (the default), then all arguments to :meth:`done` are
75+ /// as possible until cycles block more progress.
76+ /// :param bool reverse: If ``False`` (the default), perform a regular
77+ /// topological ordering, i.e. for a directed edge ``A -> B`` the ``A`` appears
78+ /// before the ``B``. If ``True``, the ordering will be a reversed topological
79+ /// ordering, i.e. for a directed edge ``A -> B``, the ``B`` appears before the ``A``.
80+ /// :param Iterable[int] initial: By default, the topological ordering will
81+ /// include all nodes in the graph. If ``initial`` node indices are provided, the
82+ /// ordering will only include those nodes and any nodes that are dominated by
83+ /// them. In this case, the first output from :meth:`get_ready()` will match
84+ /// the initial set, and any node with a natural in-degree of zero will be excluded
85+ /// from the output if it is not part of the initial set. Additionally, providing an
86+ /// initial set where the nodes have even a partial topological order among
87+ /// themselves will raise a :exc:`ValueError`, although this may not be detected until
88+ /// a call to :meth:`done()`.
89+ /// :param bool check_args: If ``True`` (the default), then all arguments to :meth:`done()` are
8190/// checked for validity, and a :exc:`ValueError` is raised if any were not ready, already
8291/// done, or not indices of the circuit. If ``False``, the tracking for this is disabled,
8392/// which can provide a meaningful performance and memory improvement, but the results will
@@ -160,22 +169,26 @@ impl TopologicalSorter {
160169
161170 /// Return ``True`` if more progress can be made and ``False`` otherwise.
162171 ///
163- /// Progress can be made if either there are still nodes ready that haven't yet
164- /// been returned by "get_ready" or the number of nodes marked "done" is less than the
165- /// number that have been returned by "get_ready".
172+ /// Progress can be made if either there are still nodes that are ready and
173+ /// haven't yet been returned by :meth:`get_ready()`, or if the number of
174+ /// nodes marked :meth:`done()` is lower than the number of nodes that have
175+ /// been returned by :meth:`get_ready()`.
176+ ///
177+ /// :returns: ``True`` if further progress is possible, ``False`` otherwise.
178+ /// :rtype: `bool`
166179 fn is_active ( & self ) -> bool {
167180 self . num_finished < self . num_passed_out || !self . ready_nodes . is_empty ( )
168181 }
169182
170183 /// Return a list of all the nodes that are ready.
171184 ///
172- /// Initially it returns all nodes with no predecessors; once those are marked
173- /// as processed by calling " done", further calls will return all new nodes that
174- /// have all their predecessors already processed. Once no more progress can be made,
175- /// empty lists are returned.
185+ /// Initially it returns all nodes with no predecessors; once those are
186+ /// marked as processed by calling :meth:` done()`, subsequent calls will
187+ /// return any new nodes that have all their predecessors already processed.
188+ /// Once no more progress can be made, an empty list is returned.
176189 ///
177190 /// :returns: A list of node indices of all the ready nodes.
178- /// :rtype: List
191+ /// :rtype: `list[int]`
179192 fn get_ready < ' py > ( & mut self , py : Python < ' py > ) -> PyResult < Bound < ' py , PyList > > {
180193 self . num_passed_out += self . ready_nodes . len ( ) ;
181194 if let Some ( node2state) = self . node2state . as_mut ( ) {
@@ -191,21 +204,21 @@ impl TopologicalSorter {
191204 }
192205 }
193206
194- /// Marks a set of nodes returned by " get_ready" as processed.
207+ /// Marks a set of nodes returned by :meth:` get_ready()` as processed.
195208 ///
196- /// This method unblocks any successor of each node in * nodes* for being returned
197- /// in the future by a call to " get_ready" .
209+ /// This method unblocks any successor of each node in `` nodes`` for being
210+ /// returned in the future by a call to :meth:` get_ready()` .
198211 ///
199- /// :param nodes: A node index or list of node indices to mark as done.
200- /// :type nodes: int | list[int]
212+ /// :param int | list[int] nodes: A node index or list of node indices to be
213+ /// marked as done.
201214 ///
202- /// :raises `ValueError`: If any node in * nodes* has already been marked as
203- /// processed by a previous call to this method or node has not yet been returned
204- /// by " get_ready" .
205- /// :raises `ValueError`: If one of the given ``initial`` nodes is a direct successor of one
206- /// of the nodes given to :meth:`done`. This can only happen if the ``initial`` nodes had
207- /// even a partial topological ordering amongst themselves, which is not a valid
208- /// starting input.
215+ /// :raises `ValueError`: If any node in `` nodes`` has already been marked
216+ /// as processed by a previous call to this method or node has not yet been
217+ /// returned by :meth:` get_ready()`` .
218+ /// :raises `ValueError`: If one of the given ``initial`` nodes is a direct
219+ /// successor of one of the nodes given to :meth:`done() `. This can only
220+ /// happen if the ``initial`` nodes had even a partial topological ordering
221+ /// amongst themselves, which is not a valid starting input.
209222 fn done ( & mut self , nodes : & Bound < PyAny > ) -> PyResult < ( ) > {
210223 if let Ok ( node) = nodes. extract :: < usize > ( ) {
211224 self . done_single ( nodes. py ( ) , NodeIndex :: new ( node) )
0 commit comments