66from dataclasses import dataclass , field
77from typing import TYPE_CHECKING , Any , TypeAlias
88
9- import networkx as nx
9+ import rustworkx as rx
1010import yaml
1111from pydantic import (
1212 SerializeAsAny ,
@@ -37,7 +37,8 @@ class Pipeline:
3737 """Pipeline representation."""
3838
3939 _component_index : dict [str , PipelineComponent ] = field (default_factory = dict )
40- _graph : nx .DiGraph [str ] = field (default_factory = nx .DiGraph )
40+ _graph : rx .PyDiGraph [str , None ] = field (default_factory = rx .PyDiGraph )
41+ _node_index : dict [str , int ] = field (default_factory = dict )
4142
4243 @property
4344 def step_names (self ) -> list [str ]:
@@ -118,23 +119,23 @@ async def run_graph_layers(
118119 for layer_components in pending_layers :
119120 await run_layer_parallel (layer_components )
120121
121- graph : nx . DiGraph [ str ] = self ._graph .copy ()
122+ graph = self ._graph .copy ()
122123
123124 # We add an extra node to the graph, connecting all the leaf nodes to it
124125 # in that way we make this node the root of the graph, avoiding backtracking
125- root_node = "root_node_bfs"
126- graph .add_node (root_node )
126+ root_node = graph .add_node ("root_node_bfs" )
127127
128- for node in graph :
129- predecessors = list (graph .predecessors (node ))
130- if not predecessors :
131- graph .add_edge (root_node , node )
128+ for node in graph .node_indices ():
129+ if node != root_node and not list (graph .predecessors (node )):
130+ graph .add_edge (root_node , node , None )
132131
133- layers_graph : list [ list [ str ]] = list (nx .bfs_layers (graph , root_node ))
132+ layers_graph = list (rx .bfs_layers (graph , [ root_node ] ))
134133
135134 sorted_layers : list [list [PipelineComponent ]] = []
136135 for layer in layers_graph [1 :]:
137- if parallel_components := self .__get_parallel_components_from (layer ):
136+ if parallel_components := self .__get_parallel_components_from (
137+ [graph [idx ] for idx in layer ]
138+ ):
138139 sorted_layers .append (parallel_components )
139140
140141 if reverse :
@@ -158,22 +159,27 @@ def __iter__(self) -> Iterator[PipelineComponent]:
158159 def __len__ (self ) -> int :
159160 return len (self .components )
160161
162+ def __get_or_add_node (self , node_id : str ) -> int :
163+ if node_id not in self ._node_index :
164+ self ._node_index [node_id ] = self ._graph .add_node (node_id )
165+ return self ._node_index [node_id ]
166+
161167 def __add_to_graph (self , component : PipelineComponent ):
162- self ._graph . add_node (component .id )
168+ node = self .__get_or_add_node (component .id )
163169
164170 for input_topic in component .inputs :
165- self .__add_input (input_topic .id , component . id )
171+ self .__add_input (input_topic .id , node )
166172
167173 for output_topic in component .outputs :
168- self .__add_output (output_topic .id , component . id )
174+ self .__add_output (output_topic .id , node )
169175
170- def __add_output (self , topic_id : str , source : str ) -> None :
171- self ._graph . add_node (topic_id )
172- self ._graph .add_edge (source , topic_id )
176+ def __add_output (self , topic_id : str , source : int ) -> None :
177+ topic = self .__get_or_add_node (topic_id )
178+ self ._graph .add_edge (source , topic , None )
173179
174- def __add_input (self , topic_id : str , target : str ) -> None :
175- self ._graph . add_node (topic_id )
176- self ._graph .add_edge (topic_id , target )
180+ def __add_input (self , topic_id : str , target : int ) -> None :
181+ topic = self .__get_or_add_node (topic_id )
182+ self ._graph .add_edge (topic , target , None )
177183
178184 def __get_parallel_components_from (
179185 self , layer : list [str ]
@@ -187,7 +193,7 @@ def gen_parallel_components() -> Iterator[PipelineComponent]:
187193 return list (gen_parallel_components ())
188194
189195 def __validate_graph (self ) -> None :
190- if not nx .is_directed_acyclic_graph (self ._graph ):
196+ if not rx .is_directed_acyclic_graph (self ._graph ):
191197 msg = "Pipeline is not a valid DAG."
192198 raise ValueError (msg )
193199
0 commit comments