class_docstr: Trace all indice information for every node.
  
  Indice is a logical concept. Equal dims can been treated as one indice.
  eg. dim(x1) = [a, b, c]
      dim(x2) = [d, e, f]
      and we have x3 = x1 * x2.
      then a=d, b=e, c=f, due to the broadcast property,
      dim(x1)=dim(x2)=dim(x3)=[a, b, c]
  This class will record every node's dims' indice, compute and source.
  
  Attributes:
      node_list (List)
      indice_trace_list (List): [{"indice": [...], "compute": [...], "source": [...]}, {...}]
      indice_view_list (Dict): not used for now
      indice_count (int): record indice number
  
  Args:
      node_list (List)
class_docstr_tok: ["Trace","all","indice","information","for","every","node",".","Indice","is","a","logical","concept",".","Equal","dims","can","been","treated","as","one","indice",".","eg",".","dim","(","x1",")","=","[","a",",","b",",","c","]","dim","(","x2",")","=","[","d",",","e",",","f","]","and","we","have","x3","=","x1","*","x2",".","then","a=d",",","b=e",",","c=f",",","due","to","the","broadcast","property",",","dim","(","x1",")","=dim","(","x2",")","=dim","(","x3",")","=","[","a",",","b",",","c","]","This","class","will","record","every","node","'s","dims","'","indice",",","compute","and","source",".","Attributes",":","node_list","(","List",")","indice_trace_list","(","List",")",":","[","{","``","indice","''",":","[","...","]",",","``","compute","''",":","[","...","]",",","``","source","''",":","[","...","]","}",",","{","...","}","]","indice_view_list","(","Dict",")",":","not","used","for","now","indice_count","(","int",")",":","record","indice","number","Args",":","node_list","(","List",")"]
docstr: Assign indice for einsum op.
  
  Args:
      node (node)
      node_idx (int)
docstr_tok: ["Assign","indice","for","einsum","op",".","Args",":","node","(","node",")","node_idx","(","int",")"]
code: def _assign_einsum_indice(self, node, idx):
      """
      Assign indice for einsum op.
  
      Args:
          node (node)
          node_idx (int)
      """
      patterns = node.args[0]
      input_nodes = node.args[1:]
  
      patterns = patterns.replace(" ", "")
      left, right = patterns.split("->")
      left = left.split(",")
  
      if "..." in right:
          replace_list = "!@#$%^&*"
          target_len = len(get_node_shape(node))
          add_len = target_len - len(right) + 3
          replace_str = replace_list[:add_len]
          right = right.replace("...", replace_str)
          for ll in range(len(left)):
              left[ll] = left[ll].replace("...", replace_str)
  
      all_index = []
      for i in left:
          for c in i:
              all_index.append(c)
      all_index = set(all_index)
  
      for right_idx, right_indice in enumerate(right):
          for left_idx, left_str in enumerate(left):
              if right_indice in left_str:
                  source_idx = left_str.index(right_indice)
                  self._inherit_indice(
                      input_nodes[left_idx], source_idx, node, right_idx
                  )
  
imports: import copy
  from typing import Dict, List
  from torch.fx.node import Node
  from .utils import NodeMgr, find_first_tensor_arg, flat_list, get_module_node_name, get_node_name, get_node_shape
label_desc: Use image node_id 31 for calling the TraceIndice obj's underlying member method code with example usage: obj._assign_einsum_indice(node, idx) without return types