@@ -43,7 +43,7 @@ def _get_wf_name(bold_fname, prefix):
4343
4444 fname = split_filename (bold_fname )[1 ]
4545 fname_nosub = '_' .join (fname .split ('_' )[1 :- 1 ])
46- return f" { prefix } _{ fname_nosub .replace ('-' , '_' )} _wf"
46+ return f' { prefix } _{ fname_nosub .replace ("-" , "_" )} _wf'
4747
4848
4949def update_dict (orig_dict , new_dict ):
@@ -70,3 +70,99 @@ def update_dict(orig_dict, new_dict):
7070 updated_dict [key ] = value
7171
7272 return updated_dict
73+
74+
75+ def find_shortest_path (space_pairs , start , end ):
76+ """Find the shortest path between two spaces in a list of space pairs.
77+
78+ Parameters
79+ ----------
80+ space_pairs : list of tuples
81+ List of tuples where each tuple contains two spaces of the form (from, to).
82+ start : str
83+ The starting space.
84+ end : str
85+ The ending space.
86+
87+ Returns
88+ -------
89+ list
90+ List of indices that represent the shortest path between the two spaces.
91+
92+ Raises
93+ ------
94+ ValueError
95+ If no path exists between the two spaces.
96+
97+ Examples
98+ --------
99+ >>> space_pairs = [("a", "b"), ("a", "c"), ("b", "d"), ("c", "d")]
100+ >>> find_shortest_path(space_pairs, "a", "d")
101+ [0, 2]
102+ """
103+ from collections import deque
104+
105+ # Create a graph from the space pairs and keep track of indices
106+ graph = {}
107+ index_map = {}
108+ for index , (src , dst ) in enumerate (space_pairs ):
109+ if src not in graph :
110+ graph [src ] = []
111+ graph [src ].append (dst )
112+ if src not in index_map :
113+ index_map [src ] = []
114+ index_map [src ].append (index )
115+
116+ # Perform BFS to find the shortest path
117+ queue = deque ([(start , [start ], [])])
118+ visited = set ()
119+
120+ while queue :
121+ current , path , indices = queue .popleft ()
122+ if current == end :
123+ return indices
124+ if current not in visited :
125+ visited .add (current )
126+ for neighbor , idx in zip (
127+ graph .get (current , []), index_map .get (current , []), strict = False
128+ ):
129+ queue .append ((neighbor , path + [neighbor ], indices + [idx ]))
130+
131+ raise ValueError (f'No path exists between { start } and { end } ' )
132+
133+
134+ def get_transforms (source , target , local_transforms = None ):
135+ """Get the transforms required to go from source to target space."""
136+ import templateflow .api as tflow
137+ from bids .layout import Entity , parse_file_entities
138+
139+ query = [
140+ Entity ('template' , 'tpl-([a-zA-Z0-9]+)' ),
141+ Entity ('from' , 'from-([a-zA-Z0-9]+)' ),
142+ ]
143+
144+ all_transforms = local_transforms or []
145+
146+ templates = tflow .get_templates ()
147+ for template in templates :
148+ template_transforms = tflow .get (template , suffix = 'xfm' , extension = 'h5' )
149+ if not isinstance (template_transforms , list ):
150+ template_transforms = [template_transforms ]
151+ all_transforms += template_transforms
152+
153+ links = []
154+ for transform in all_transforms :
155+ entities = parse_file_entities (transform , entities = query )
156+ link = (entities ['from' ], entities ['template' ])
157+ links .append (link )
158+
159+ path = None
160+ try :
161+ path = find_shortest_path (links , source , target )
162+ print ('Shortest path:' , path )
163+ except ValueError as e :
164+ print (e )
165+
166+ selected_transforms = [all_transforms [i ] for i in path ]
167+
168+ return selected_transforms
0 commit comments