3131from pydantic import ConfigDict , Discriminator , Tag , computed_field
3232import sympy
3333
34+ from accelforge .frontend .renames import EinsumName
3435from accelforge .util ._basetypes import (
3536 # Parsing helpers for the input files.
3637 EvalableModel ,
@@ -318,7 +319,13 @@ class Loop(MappingNode):
318319 rank_variable : set [RankVariable ] | RankVariable
319320 """ The rank variable(s) iterated over in this loop. This may be a
320321 single rank variable, or a set of rank variables if the loop is shared between
321- multiple Einsums. """
322+ multiple Einsums.
323+
324+ NOTE FOR DEVELOPERS: If the rank variable is a set DURING PMAPPIN GENERATION, then
325+ it means that the loop is a placeholder for multiple loops in the given Einsum. They
326+ will be split into multiple loops later. If the rank variable
327+
328+ """
322329
323330 tile_shape : EvalsTo [sympy .Symbol | sympy .Expr | int | str ] = "symbol"
324331 """
@@ -353,6 +360,12 @@ class Loop(MappingNode):
353360 tile_shape for details.
354361 """
355362
363+ _einsum_to_rank_variables : dict [EinsumName , set [RankVariable ]] = {}
364+ """
365+ If there are multiple rank variables in this loop, this dictionary says which rank
366+ variables belong to which Einsum.
367+ """
368+
356369 _calculated_n_iterations : (
357370 Literal ["symbol" ] | sympy .Symbol | sympy .Expr | int | str | None
358371 ) = None
@@ -1073,8 +1086,11 @@ def _pop_loop_group(groups: list[list[MappingNode]]) -> list[MappingNode]:
10731086 # variables and assume that rank variable translation would fix it.
10741087 assert len (my_loop_group ) == 1 or len (other_loop_group ) == 1
10751088 has_one , may_not_have_one = my_loop_group , other_loop_group
1089+
1090+ switched = False
10761091 if len (has_one ) != 1 :
10771092 has_one , may_not_have_one = other_loop_group , my_loop_group
1093+ switched = True
10781094
10791095 l = copy .deepcopy (has_one .pop (0 ))
10801096 l .rank_variable = (
@@ -1093,10 +1109,21 @@ def _pop_loop_group(groups: list[list[MappingNode]]) -> list[MappingNode]:
10931109 f"Warning. Matching loops { l } and { l2 } . Need rank variable translation here."
10941110 )
10951111
1112+ my_rv = l .rank_variable if isinstance (l .rank_variable , set ) else set ([l .rank_variable ])
1113+ other_rv = l2 .rank_variable if isinstance (l2 .rank_variable , set ) else set ([l2 .rank_variable ])
1114+ if switched :
1115+ my_rv , other_rv = other_rv , my_rv
1116+
10961117 may_not_have_one .remove (l2 )
10971118 rv = l2 .rank_variable
1119+ for compute in self .get_nodes_of_type (Compute ):
1120+ for r in my_rv :
1121+ l ._einsum_to_rank_variables [compute .einsum ] = r
10981122 rv = rv if isinstance (rv , set ) else set ([rv ])
10991123 l .rank_variable = l .rank_variable | rv
1124+ for compute in other .get_nodes_of_type (Compute ):
1125+ for r in other_rv :
1126+ l ._einsum_to_rank_variables [compute .einsum ] = r
11001127 to_add = [l ]
11011128
11021129 zipped_groups .append (to_add )
@@ -1542,15 +1569,18 @@ def split_reservations(self):
15421569 new_nodes .append (node )
15431570 self .nodes = new_nodes
15441571
1545- def split_loop_with_multiple_rank_variables (self , stride_and_halo : dict [ str , tuple [ int , int ]] ):
1572+ def split_loop_with_multiple_rank_variables (self , einsum_name : EinsumName ):
15461573 new_nodes = []
15471574 my_rank_variables = set (x [1 ] for x in stride_and_halo )
15481575 for node in self .nodes :
15491576 if isinstance (node , Loop ) and isinstance (node .rank_variable , set ):
1550- ranks_in_stride_and_halo = node .rank_variable & my_rank_variables
1551- assert len (ranks_in_stride_and_halo ) == 1 , f"Expected 1 rank in stride and halo, got { len (ranks_in_stride_and_halo )} "
1577+ if einsum_name not in node ._einsum_to_rank_variables :
1578+ raise ValueError (
1579+ f"Loop { node .compact_str ()} has multiple rank variables. Make "
1580+ f"sure to populate _einsum_to_rank_variables for this loop."
1581+ )
15521582 new_node = copy .copy (node )
1553- new_node .rank_variable = ranks_in_stride_and_halo . pop ()
1583+ new_node .rank_variable = node . _einsum_to_rank_variables [ einsum_name ]
15541584 new_nodes .append (new_node )
15551585 else :
15561586 new_nodes .append (node )
0 commit comments